Що таке оператор Ruby <=> (космічний корабель)?


262

Що таке <=>оператор Ruby (космічний корабель)? Чи реалізований оператор будь-якими іншими мовами?


1
А як щодо порівняння масивів? У книзі сказано: "порівнює елемент за елементом, повертає 0, якщо дорівнює, -1 якщо менше, 1 якщо більше, але що робити [1,3,2] <=> [2,2,2]?
SF.

3
@SF, коли люди порівнюють масиви, вони зазвичай мають на увазі порівняння лексикографічно (як у словнику, тобто [1,3,2] <[2,2,2], оскільки перші елементи різні). Рідко (fe в Matlab) порівняння масиву повертає масив результатів на елемент; у цьому випадку: [-1, 1, 0].
liori

Зауважте, що масиви, що містять нульові елементи, порівнянні, якщо елементи перед будь-яким нулем відрізняються, і не порівнянні, якщо нуль потрібно порівнювати з ненульовим. Тобто [1, нуль] <=> [2, 3] => -1, але [1, нуль] <=> [1, 3] => нуль. Це смокче, в основному.
cliffordheath

Порівнюючи масиви на зразок [1,nil] <=> [1,3]ви отримуєте a nilчерез послідовність алгоритму, порівнюючи кожен елемент по черзі, поки <=>результат НЕ буде 0. Рубі не може оголосити менше або більше, ніж у цьому прикладі, оскільки порівняння просто неможливо зробити. nilСлід розглядати як «не дорівнює». Якщо ви знаєте щось про дані, і, наприклад, хочете ставитися nilдо них 0, Ruby робить це легко.
lilole

Відповіді:


359

Перл, ймовірно, була першою мовою, яка його використовувала. Groovy - ще одна мова, яка її підтримує. В принципі , замість того , щоб повернутися 1( true) або 0( false) в залежності від того , аргументи рівні або нерівні, оператор космічного корабля повернеться 1, 0або в −1залежності від значення лівого аргументу по відношенню до правого аргументу.

a <=> b :=
  if a < b then return -1
  if a = b then return  0
  if a > b then return  1
  if a and b are not comparable then return nil

Це корисно для сортування масиву.


27
Саме так. Я вважаю це дуже елегантною версією Java's Comprable.
Майк Ределл

12
аналог в c # є Ізрівнянний.CompareTo
Сергій Мирвода

1
Насправді я думаю, що будь-яке негативне чи позитивне значення можна повернути. 0 все ще означає рівність.
суперлюмінація

1
@superluminary На відміну від strcmp функції C, x <=> y ​​призначений спеціально для повернення лише -1, 0, 1 або нуль, якщо x і y не порівнянні (у Ruby та будь-яких інших мовах, які використовують його AFAIK). Це дозволяє легко перевантажувати оператора, наприклад, для Ruby's Comprable mixin. У Perl, звідки, найімовірніше, бере свій початок оператор, він використовувався в основному для спрощення синтаксису "сортування BLOCK LIST". БЛОК - це підпрограма, яка може повернути будь-яке додатне число, від’ємне число або 0 залежно від того, як слід сортувати елементи списку. Оператор космічного корабля зручно використовувати в блоці.
TonyArra

2
Зауважте, що якщо два порівняних об'єкта не порівнянні, ви отримаєте нуль
gamov

70

Метод космічного корабля корисний, коли ви визначаєте його у власному класі та включаєте модуль Порівняння . Потім ваш клас отримує >, < , >=, <=, ==, and between?методи безкоштовно.

class Card
  include Comparable
  attr_reader :value

  def initialize(value)
    @value = value
  end

  def <=> (other) #1 if self>other; 0 if self==other; -1 if self<other
    self.value <=> other.value
  end

end

a = Card.new(7)
b = Card.new(10)
c = Card.new(8)

puts a > b # false
puts c.between?(a,b) # true

# Array#sort uses <=> :
p [a,b,c].sort # [#<Card:0x0000000242d298 @value=7>, #<Card:0x0000000242d248 @value=8>, #<Card:0x0000000242d270 @value=10>]

20

Це загальний оператор порівняння. Він повертає або -1, 0, або +1 залежно від того, чи є його приймач меншим, рівним або більшим, ніж його аргумент.


18

Я поясню на простому прикладі

  1. [1,3,2] <=> [2,2,2]

    Ruby почне порівнювати кожен елемент обох масивів з лівої сторони. 1для лівого масиву менше, ніж 2для правого масиву. Отже лівий масив менший, ніж правий масив. Вихід буде -1.

  2. [2,3,2] <=> [2,2,2]

    Як вище, він спочатку порівняє перший елемент, який є рівним, потім порівняє другий елемент, у цьому випадку другий елемент лівого масиву більший, отже, і вихід 1.


це просто порівняти перший лівий елемент кожного масиву чи продовжувати порівнювати й інші елементи? хороше пояснення
Кіт Бутовський

1
@KickButtowski продовжує порівнювати інші елементи, якщо не знайде нерівне число.
Аніл Маурія

5

Оскільки цей оператор зводить порівняння до цілого виразу, він забезпечує найбільш загальний спосіб сортування висхідних чи низхідних на основі кількох стовпців / атрибутів.

Наприклад, якщо у мене є масив об'єктів, я можу робити такі дії:

# `sort!` modifies array in place, avoids duplicating if it's large...

# Sort by zip code, ascending
my_objects.sort! { |a, b| a.zip <=> b.zip }

# Sort by zip code, descending
my_objects.sort! { |a, b| b.zip <=> a.zip }
# ...same as...
my_objects.sort! { |a, b| -1 * (a.zip <=> b.zip) }

# Sort by last name, then first
my_objects.sort! { |a, b| 2 * (a.last <=> b.last) + (a.first <=> b.first) }

# Sort by zip, then age descending, then last name, then first
# [Notice powers of 2 make it work for > 2 columns.]
my_objects.sort! do |a, b|
      8 * (a.zip   <=> b.zip) +
     -4 * (a.age   <=> b.age) +
      2 * (a.last  <=> b.last) +
          (a.first <=> b.first)
end

Цю основну схему можна узагальнити для сортування за будь-якою кількістю стовпців у будь-якій перестановці висхідного / низхідного на кожному.


Приємні приклади, просто те, що останній працює не так, як очікувалося. Коефіцієнти мають бути потужностями двох у порядку зменшення, тобто 8, -4, 2, 1. Так, як ви це написали (з факторами 4, -3,2,1), наприклад, "вік + прізвище" налічує більше, ніж "zip "...
Ельмар Зандер

Я не думаю, що ці числа означають те, що ви думаєте, що вони означають. Кожен коефіцієнт помножує сигнуму, яка буде -1, 0 або 1. Повноваження 2 тут не мають значення. -3 * (a.age <=> b.age) точно такий же, як 3 * (b.age <=> a.age). Ознака результату - це те, що робить його вниз або desc.
lilole

Ні, це має велике значення. Коефіцієнт для zip повинен бути більшим, ніж (абсолютна) сума всіх інших факторів, а коефіцієнт для віку повинен бути більшим, ніж (абсолютна) сума факторів останнього і першого тощо. І найменша послідовність чисел, яка відповідає, - це послідовність повноважень двох ... І BTW, якби ви уважно прочитали мій коментар, ви побачили б, що я включив знак мінус ...
Ельмар Зандер,

1
Гаразд, можливо, я детальніше про це детальніше: з коефіцієнтами (4, -3,2,1) та результатами космічного корабля op (1,1, -1, -1) зважена сума дорівнює -2, але це має бути позитивним! Інакше більший поштовий блискавок постане перед меншим. Це не відбудеться з факторами (8, -4,2,1).
Ельмар Зандер

1
Так, я бачу, якщо сортувати за> 2 стовпцями, тоді необхідні повноваження 2. Дякуємо, що допомогли виправити це. Вибачте світ, якщо сортування ваших 3 чи більше стовпців виявилося неправильним.
lilole

-2

Що таке <=> (Оператор «Космічного корабля»)

За даними RFC, яка представила оператора , $ a <=>$ b

 -  0 if $a == $b
 - -1 if $a < $b
 -  1 if $a > $b

 - Return 0 if values on either side are equal
 - Return 1 if value on the left is greater
 - Return -1 if the value on the right is greater

Приклад:

//Comparing Integers

echo 1 <=> 1; //ouputs 0
echo 3 <=> 4; //outputs -1
echo 4 <=> 3; //outputs 1

//String Comparison

echo "x" <=> "x"; // 0
echo "x" <=> "y"; //-1
echo "y" <=> "x"; //1

БІЛЬШЕ:

// Integers
echo 1 <=> 1; // 0
echo 1 <=> 2; // -1
echo 2 <=> 1; // 1

// Floats
echo 1.5 <=> 1.5; // 0
echo 1.5 <=> 2.5; // -1
echo 2.5 <=> 1.5; // 1

// Strings
echo "a" <=> "a"; // 0
echo "a" <=> "b"; // -1
echo "b" <=> "a"; // 1

echo "a" <=> "aa"; // -1
echo "zz" <=> "aa"; // 1

// Arrays
echo [] <=> []; // 0
echo [1, 2, 3] <=> [1, 2, 3]; // 0
echo [1, 2, 3] <=> []; // 1
echo [1, 2, 3] <=> [1, 2, 1]; // 1
echo [1, 2, 3] <=> [1, 2, 4]; // -1

// Objects
$a = (object) ["a" => "b"]; 
$b = (object) ["a" => "b"]; 
echo $a <=> $b; // 0
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.