I recently came across a piece of code that used

``array.sort{|x,y| y <=> x}``

to sort an array of integers in descending order. I looked up the <=> operator and understand that it returns three different values, -1, 0, or 1, depending on whether or not one value is less than, greater to, or equal to the other other value.

But I cannot reason out why this would make the above code sort the array in descending order, but know that it definitely does thanks to IRB. What's going on here? Can somebody explain this to me?

For the same reasons that this:

``````array.sort{|x,y| x <=> y}
``````

Sorts by ascending order.

Take this program for example:

``````[1,5,2,4,3].sort do |x,y|
puts "---"
puts x
puts y
puts x <=> y
x <=> y
end
``````

It'll output the two numbers that it's comparing, and then the result of the `<=>` during the sort. It outputs this:

``````---
1
2
-1 # 1 is less than 2
---
2
3
-1 # 2 is less than 3
---
5
2
1 # 5 is greater than 1
---
4
2
1 # 4 is greater than 2
---
5
4
1 # 5 is greater than 4
---
4
3
1 # 4 is greater than 3
``````

If you reverse the order of `x <=> y` to be `y <=> x`, you're going to get the opposite result.

Because you did y <=> x, not x <=> y. Order of arguments is important.

I've chosen to give an answer that I hope will be understandable to most Ruby newbies.

Array#sort compares each pair of elements in the array. For each pair of elements `x,y`, `sort`'s block returns `-1` if `x` precedes `y` in the sort, `1` if `y` precedes `x` and `0` if either can precede the other. If no block is given, `sort` employs the block:

``````{ |x,y| x <=> y }
``````

If, for example, `x` and `y` are strings, the method String#<=> might be defined like this:

``````class String
def <=>(other)
case
when self < other then -1
when self > other then  1
else 0
end
end
end
``````

Similarly, Array#<=> is invoked if `x` and `y` are arrays, and so on. For `Fixnum`s, `Bignum`s and `Float`s (all of which are from classes that descend from `Numeric`), the method Numeric#<=> is used, so that the array being sorted can contain a mix of those three data types.

If `sort`'s block is:

``````{ |x,y| y <=> x }
``````

the block returns the values shown here (with the values for the default `x <=> y` shown for comparison):

Now suppose we wish to sort the array `[2,3,1,2]`. For the default `sort`, the sort block with `x <=> y` returns the values shown here:

which causes `sort` to return `[1,2,2,3]`. If the sort block is

``````{ |x,y| y <=> x }
``````

the sort block returns these values:

causing `sort` to return `[3,2,2,1]`.

Top