Toán tử Ruby <=> (tàu vũ trụ) là gì?


262

<=>Toán tử Ruby (tàu vũ trụ) là gì? Là nhà điều hành thực hiện bởi bất kỳ ngôn ngữ khác?


1
Bây giờ những gì về so sánh mảng? Nó đã nói trong cuốn sách "so sánh các yếu tố theo yếu tố, trả về 0 nếu bằng nhau, -1 nếu nhỏ hơn, 1 nếu lớn hơn, nhưng còn gì [1,3,2] <=> [2,2,2]?
SF.

3
@SF, khi mọi người so sánh các mảng, họ thường có nghĩa là so sánh từ vựng (như trong từ điển, tức là [1,3,2] <[2,2,2] vì các yếu tố đầu tiên khác nhau). Hiếm khi so sánh mảng (trong Matlab) trả về một mảng kết quả cho mỗi phần tử; trong trường hợp này: [-1, 1, 0].
liori

Lưu ý rằng Mảng có chứa các phần tử nil có thể so sánh được nếu các phần tử trước bất kỳ số 0 nào khác nhau và không thể so sánh nếu một số không phải được so sánh với số không. Tức là [1, nil] <=> [2, 3] => -1, nhưng [1, nil] <=> [1, 3] => không. Điều này hút, về cơ bản.
vách đá vào

Khi so sánh các mảng như [1,nil] <=> [1,3]bạn nhận được nilvì tính nhất quán của thuật toán, so sánh lần lượt từng phần tử cho đến khi <=>kết quả là KHÔNG 0. Không có cách nào để Ruby tuyên bố ít hơn hoặc lớn hơn trong ví dụ này, vì việc so sánh đơn giản là không thể thực hiện được. Các nilphải được coi là "không công bằng". Nếu bạn biết điều gì đó về dữ liệu, và ví dụ muốn điều trị nilnhư 0, Ruby làm cho dễ dàng.
lilole

Câu trả lời:


359

Perl có khả năng là ngôn ngữ đầu tiên sử dụng nó. Groovy là một ngôn ngữ khác hỗ trợ nó. Về cơ bản thay vì trả lại 1( true) hoặc 0( false) tuỳ thuộc vào việc các đối số đều bình đẳng hay bất bình đẳng, các nhà điều hành tàu vũ trụ sẽ trở lại 1, 0hoặc −1tùy thuộc vào giá trị của các đối số bên trái so với lập luận đúng.

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

Nó rất hữu ích để sắp xếp một mảng.


27
Chính xác. Tôi nghĩ về nó như là một phiên bản so sánh rất thanh lịch của Java.
Mike Reedell

12
tương tự trong c # là IComparable.CompareTo
Sergey Mirvoda

1
Trên thực tế tôi nghĩ rằng bất kỳ giá trị tiêu cực hoặc tích cực có thể được trả lại. 0 vẫn có nghĩa là bình đẳng.
siêu sáng

1
@superluminary Không giống như hàm strcmp của C, x <=> y ​​được thiết kế riêng để chỉ trả về -1, 0, 1 hoặc nil nếu x và y không thể so sánh được (trong Ruby và bất kỳ ngôn ngữ nào khác sử dụng AFAIK). Điều này giúp dễ dàng quá tải toán tử, chẳng hạn như đối với mixin so sánh của Ruby. Trong Perl, nơi toán tử có khả năng bắt nguồn, nó được sử dụng chủ yếu để đơn giản hóa cú pháp "sắp xếp BLOCK LIST". BLOCK là chương trình con có thể trả về bất kỳ số dương, số âm hoặc 0 tùy thuộc vào cách sắp xếp các mục danh sách. Toán tử Spaceship thuận tiện để sử dụng trong khối.
TonyArra

2
Lưu ý rằng nếu hai đối tượng được so sánh không thể so sánh được, bạn sẽ nhận được một con số không
gamov

70

Phương thức tàu vũ trụ rất hữu ích khi bạn định nghĩa nó trong lớp của riêng bạn và bao gồm mô-đun so sánh . Lớp của bạn sau đó được các >, < , >=, <=, ==, and between?phương thức miễn phí.

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

Đó là một toán tử so sánh chung. Nó trả về -1, 0 hoặc +1 tùy thuộc vào việc bộ thu của nó nhỏ hơn, bằng hoặc lớn hơn đối số của nó.


18

Tôi sẽ giải thích với ví dụ đơn giản

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

    Ruby sẽ bắt đầu so sánh từng yếu tố của cả hai mảng từ phía bên trái. 1cho mảng bên trái nhỏ hơn 2mảng bên phải. Do đó mảng bên trái nhỏ hơn mảng bên phải. Đầu ra sẽ được -1.

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

    Như trên, trước tiên nó sẽ so sánh phần tử thứ nhất bằng nhau sau đó nó sẽ so sánh phần tử thứ hai, trong trường hợp này phần tử thứ hai của mảng bên trái lớn hơn do đó đầu ra là 1.


Có phải nó chỉ so sánh phần tử bên trái đầu tiên của mỗi mảng hoặc tiếp tục so sánh các phần tử khác không? giải thích tốt
Kick Buttowski

1
@KickButtowski nó tiếp tục so sánh các yếu tố khác trừ khi tìm thấy một số bất đẳng thức.
Anil Maurya

5

Vì toán tử này làm giảm sự so sánh với một biểu thức số nguyên, nó cung cấp cách mục đích chung nhất để sắp xếp tăng dần hoặc giảm dần dựa trên nhiều cột / thuộc tính.

Ví dụ, nếu tôi có một mảng các đối tượng, tôi có thể làm những việc như thế này:

# `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

Mẫu cơ bản này có thể được tổng quát hóa để sắp xếp theo bất kỳ số lượng cột nào, theo bất kỳ hoán vị tăng / giảm dần trên mỗi cột.


Những ví dụ hay, chỉ là cái cuối cùng không hoạt động như mong đợi. Các yếu tố phải là sức mạnh của hai theo thứ tự giảm dần, tức là 8, -4, 2, 1. Cách bạn viết nó (với các yếu tố 4, -3,2,1), ví dụ: "tuổi + họ" được tính nhiều hơn "zip "...
Elmar Zander

Tôi không nghĩ những con số đó có nghĩa là những gì bạn nghĩ. Mỗi yếu tố nhân số tín hiệu, sẽ là -1, 0 hoặc 1. Quyền hạn của 2 không quan trọng ở đây. -3 * (a.age <=> b.age) hoàn toàn giống với 3 * (b.age <=> a.age). Dấu hiệu của kết quả là những gì làm cho nó asc hoặc desc.
lilole

Không, nó không thành vấn đề. Hệ số cho zip phải lớn hơn tổng (tuyệt đối) của tất cả các yếu tố khác và hệ số theo tuổi phải lớn hơn tổng (tuyệt đối) của các yếu tố cuối cùng và đầu tiên, v.v. Và dãy số nhỏ nhất đáp ứng đó là chuỗi lũy thừa của hai ... Và BTW nếu bạn đọc kỹ nhận xét của tôi, bạn sẽ thấy rằng tôi đã bao gồm dấu trừ ...
Elmar Zander

1
Ok, có lẽ tôi sẽ giải thích thêm một chút về điều đó: với các yếu tố (4, -3,2,1) và kết quả từ tàu vũ trụ op (1,1, -1, -1) tổng trọng số là -2, nhưng nó cần phải tích cực! Nếu không, zip lớn hơn sẽ đến trước zip nhỏ hơn. Điều này sẽ không xảy ra với các yếu tố (8, -4,2,1).
Elmar Zander

1
Bây giờ tôi hiểu rồi, nếu sắp xếp trên> 2 cột thì quyền hạn của 2 là bắt buộc. Cảm ơn đã giúp sửa lỗi này. Xin lỗi thế giới nếu sắp xếp 3 cột trở lên của bạn sai.
lilole

-2

Là gì <=> (The 'tàu vũ trụ' Nhà điều hành)

Theo RFC đã giới thiệu nhà điều hành , $ 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

Thí dụ:

//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

HƠN:

// 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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.