views:

224

answers:

5

I am having a problem understanding how array.sort{|x,y| block} works exactly,hence how to use it?

ruby-doc example:

   a = [ "d", "a", "e", "c", "b" ]
   a.sort                    #=> ["a", "b", "c", "d", "e"]
   a.sort {|x,y| y <=> x }   #=> ["e", "d", "c", "b", "a"]

thanks

+5  A: 

In your example

a.sort

is equivalent to

a.sort { |x, y| x <=> y }

As you know, to sort an array, you need to be able to compare its elements (if you doubt that, just try to implement any sort algorithm without using any comparison, no <, >, <= or >=).

The block you provide is really a function which will be called by the sort algorithm to compare two items. That is x and y will always be some elements of the input array chosen by the sort algorithm during its execution.

The sort algorithm will assume that this comparison function/block will meet the requirements for method <=>:

  • return -1 if x < y
  • return 0 if x = y
  • return 1 if x > y

Failure to provide an adequate comparison function/block will result in array whose order is undefined.

You should now understand why

a.sort { |x, y| x <=> y }

and

a.sort { |x, y| y <=> x }

return the same array in opposite orders.


To elaborate on what Tate Johnson added, if you implement the comparison function <=> on any of your classes, you gain the following

  1. You may include the module Comparable in your class which will automatically define for you the following methods: between?, ==, >=, <, <= and >.
  2. Instances of your class can now be sorted using the default (ie without argument) invocation to sort.

Note that the <=> method is already provided wherever it makes sense in ruby's standard library (Bignum, Array, File::Stat, Fixnum, String, Time, etc...).

bltxd
I think it's worth adding that `<=>` is a method defined in `Comparable` and mixed in with `String`. `Fixnum` and `Bignum` also define `<=>`. You can implement `<=>` in any class where sorting or comparrisons are necessary.
Tate Johnson
sorry, still don't get it. What is the passed x and y?
Ibrahim Hussein
The 2 elements being compared to each other.
ryeguy
I understand this. I mean what they represent in the array?
Ibrahim Hussein
I highlighted the important sentence. x and y will be 2 elements of your array, chosen by the sort algorithm itself.
bltxd
Thanks. I get it now!
Ibrahim Hussein
It's also good to note that your block can be as complicated or in depth as necessary. As long as the return value accurately reflects the behavior you'd expect from your <=> operator you can do anything you need. So if you want to sort based on a boolean or something you can evaluate that boolean and return -1 or 1 accordingly. It comes in handy.
Matt
+2  A: 

<=> is a method is ruby that returns ( self.<=>( argument ) )

  • -1 if self < argument
  • 0 if self == argument
  • 1 if self > argument

x and y are items of array. If no block is provided, the sort function uses x<=>y, otherwise the result of the block says if x should be before y.

array.sort{|x, y| some_very_complicated_method(x, y) }

Here if some_very_complicated_method(x, y) returns smth that is < 0, x is considered < than y and so on...

Draco Ater
You say x and y are items in the array. Does it mean that for example in [1,2,3,4,5] 1 and 2 are compared, then 3 and 4 and so on?thanks
Ibrahim Hussein
It means that whenever it has to compare *any* 2 items - one of them will be x and the other y. It can be 1 and 2, 3 and 5, 1 and 4...
Draco Ater
Exactly what is compared depends on the sort algorithm used. I think quicksort is used, and that performs `n log n` comparisons, and it's not easy for me to specify which comparisons are performed, and which are omitted. (If the most naive bubblesort implementation were used, you'd be pretty much guaranteed to compare every element with every other element, but that's a lot slower.)
Ken Bloom
Thanks for the help.
Ibrahim Hussein
A: 

When you have an array of, let's say, integers to sort, it's pretty straightforward for sort method to order the elements properly - smaller numbers first, bigger at the end. That's when you use ordinary sort, with no block.

But when you are sorting other objects, it may be needed to provide a way to compare (each) two of them. Let's say you have an array of objects of class Person. You probably can't tell if object bob is greater than object mike (i.e. class Person doesn't have method <=> implemented). In that case you'd need to provide some code to explain in which order you want these objects sorted to sort method. That's where the block form kicks in.

people.sort{|p1,p2| p1.age <=> p2.age}
people.sort{|p1,p2| p1.children.count <=> p2.children.count}

etc. In all these cases, sort method sorts them the same way - the same algorithm is used. What is different is comparison logic.

Mladen Jablanović
Thanks, this was really helpful.
Ibrahim Hussein
A: 

Some miscellaneous points:

  • x and y are called block parameters. The sort method basically says "I'll give you x and y, you determine whether x or y should come first, and I'll look after the boring stuff with regards to sorting"
  • <=> is called a spaceship operator.
Andrew Grimm
A: 

In:

a.sort {|x,y| y <=> x }   #=> ["e", "d", "c", "b", "a"]

what is x and y?

x and y are the elements being compared by the sorting algorithm.

This is useful to define for custom classes which element should be before the other.

For basic data ( numbers, strings , date, etc ) the natural order is predefined, but for customer element ( ie Employee ) you define who goes before who in a comparison. This block give you the chance to define that.

and what happens at y<=>x?

There, they are comparing the elements in descending order ( those with "higher" value will go first ) rather than the natural order ( x<=>y )

The <=> method stands for "compareTo" and return 0 if the elements are equivalent, or < 0 if x goes before than y or > 0 if x goes after y

OscarRyz