user2491254
user2491254

Reputation: 783

Understanding Ruby array sorting syntax

I really don't understand the following sorting method:

books = ["Charlie and the Chocolate Factory", "War and Peace", "Utopia", "A Brief History of Time", "A Wrinkle in Time"]

books.sort! { |firstBook, secondBook| firstBook <=> secondBook }

How does the this work? In the ruby books, they had one parameter for example |x| represent each of the values in the array. If there is more than one parameter (firstBook and secondBook in this example) what does it represent??

Thank you!

Upvotes: 1

Views: 1060

Answers (4)

Darshan Rivka Whittle
Darshan Rivka Whittle

Reputation: 34031

Array#sort (and sort!) called without a block will do comparisons with <=>, so the block is redundant. These all accomplish the same thing:

books.sort!
books.sort_by!{|x| x}
books.sort!{|firstBook, secondBook| firstBook <=> secondBook}

Since you are not overriding the default behavior, the second and third forms are needlessly complicated.

So how does this all work?

The first form sorts the array by using some sorting algorithm -- it's not relevant which one -- which needs to be able to compare two elements to decide which comes first. (More on this below.) It automatically, behind the scenes, follows the same logic as the third line above.

The middle form lets you choose what to sort on. For example: instead of, for each item, just sorting on that item (which is the default), you can sort on that item's length:

books.sort_by!{|title| title.length}

Then books is sorted from shortest title to longest title. If all you are doing is calling a method on each item, there's another shortcut available. This does the same thing:

books.sort_by!(&:length)

In the final form, you have control over the comparison itself. For example, you could sort backwards:

books.sort!{|first, second| second <=> first}

Why does sort need two items passed into the block, and what do they represent?

Array#sort (and sort!) with a block is how you override the comparison step of sorting. Comparison has to happen at some point during a sort in order to figure out what order to put things in. You don't need to override the comparison in most cases, but if you do, this is the form that allows that, so it needs two items passed into the block: the two items that need to be compared right now. Let's look at an example in action:

[4, 3, 2, 1].sort{|x, y| puts "#{x}, #{y}"; x <=> y}

This outputs:

4, 2
2, 1
3, 2
3, 4

This shows us that in this case, sort compared 4 and 2, then 2 and 1, then 3 and 2, and then finally 3 and 4, in order to sort the array. The precise details are irrelevant to this discussion and depend on the sorting algorithm being used, but again, all sorting algorithms need to be able to compare items in order to sort.

Upvotes: 1

Peter Alfvin
Peter Alfvin

Reputation: 29419

See http://ruby-doc.org/core-2.0/Array.html#method-i-sort for an explanation. As for a single-parameter method referred to in your books, I can only guess you were looking at sort_by. Can you give an example?

Upvotes: 0

Tala
Tala

Reputation: 8928

The block given inside {} is passed as a comparing function for method sort. |a, b| tells us that this comparing function takes 2 parameters (which is expected number of arguments since we need to compare).

This block is executed for each element in array but if we need one more argument we take next element after this.

Upvotes: 0

Dan Tao
Dan Tao

Reputation: 128317

The <=> operator returns the result of a comparison.

So "a" <=> "b" returns -1, "b" <=> "a" returns 1, and "a" <=> "a" returns 0.

That's how sort is able to determine the order of elements.

Upvotes: 4

Related Questions