Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does Ruby's sort method work with the combined comparison (spaceship) operator?

Beginning programmer here, just wanting to understand the process behind Ruby's sort method when using the spaceship operator <=>. Hope someone can help.

In the following:

array = [1, 2, 3]
array.sort { |a, b| a <=> b }

... I understand that sort is comparing a pair of numbers at a time and then returning -1 if a belongs before b, 0 if they're equal, or 1 if a should follow b.

But in the case of sorting in descending order, like so:

array.sort { |a, b| b <=> a }

... what exactly is happening? Does sort still compare a <=> b and then flip the result? Or is it interpreting the returns of -1, 0 and 1 with reversed behavior?

In other words, why does placing the variables in the block like so:

array.sort { |b, a| b <=> a }

...result in the same sorting pattern as in the first example?

like image 905
vertigokidd Avatar asked May 17 '13 01:05

vertigokidd


People also ask

How do you use the spaceship operator in Ruby?

If you aren't familiar with Ruby's spaceship operator, <=>, it compares two objects and returns 1 if the first object's value is larger, 0 if both values are equal, and -1 if the second object's value is larger. In our first example it compared 7 to 1 and returned 1 because 7 has a larger value.

How does Ruby sort work?

The Ruby sort method works by comparing elements of a collection using their <=> operator (more about that in a second), using the quicksort algorithm. You can also pass it an optional block if you want to do some custom sorting. The block receives two parameters for you to specify how they should be compared.

What sorting algorithm does Ruby use?

The Array#sort method in Ruby uses the venerable Quicksort algorithm. In its best case, Quicksort has time complexity O(n log n), but in cases where the data to be sorted is already ordered, the complexity can grow to O(n2).

What does <=> mean in Ruby?

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.


2 Answers

a <=> b will return -1 if a belongs before b, 0 if they're equal, or 1 if a should follow b.
b <=> a will return -1 if b belongs before a, 0 if they're equal, or 1 if b should follow a.

Since you are reversing the order, the output should be reversed, just like the - operator, for example. 3-5 is -2, and 5-3 is 2.

array.sort { |b, a| b <=> a } is equal to array.sort { |a, b| a <=> b } because the first argument is before the spaceship, and the second is after. Ruby doesn't care what the name of the variable is.

like image 134
tckmn Avatar answered Oct 06 '22 15:10

tckmn


Sort just does this:

comparison_block.call(elem[i],elem[j])

It doesn't know or care what your block looks like internally, but it knows which element it passed in as the first argument and which as the second, and that's what the result is based on. In a normal numeric ascending sort, calling the block with (1,0) should return 1; calling it with (0,1) should return -1. Order matters.

like image 27
Mark Reed Avatar answered Oct 06 '22 15:10

Mark Reed