What is the Ruby <=>
(spaceship) operator? Is the operator implemented by any other languages?
Since this operator reduces comparisons to an integer expression, it provides the most general purpose way to sort ascending or descending based on multiple columns/attributes.
For example, if I have an array of objects I can do things like this:
# `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
This basic pattern can be generalized to sort by any number of columns, in any permutation of ascending/descending on each.
Perl was likely the first language to use it. Groovy is another language that supports it. Basically instead of returning 1
(true
) or 0
(false
) depending on whether the arguments are equal or unequal, the spaceship operator will return 1
, 0
, or −1
depending on the value of the left argument relative to the right argument.
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
It's useful for sorting an array.
I will explain with simple example
[1,3,2] <=> [2,2,2]
Ruby will start comparing each element of both array from left hand side.
1
for left array is smaller than 2
of right array. Hence left array is smaller than right array. Output will be -1
.
[2,3,2] <=> [2,2,2]
As above it will first compare first element which are equal then it will compare second element, in this case second element of left array is greater hence output is 1
.
What is
<=>
( The 'Spaceship' Operator )
<=>
$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
Example:
//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
MORE:
// 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
It's a general comparison operator. It returns either a -1, 0, or +1 depending on whether its receiver is less than, equal to, or greater than its argument.
The spaceship method is useful when you define it in your own class and include the Comparable module. Your class then gets the >, < , >=, <=, ==, and between?
methods for free.
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>]