Що таке оператор 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.