Gavin Kistner said:
a.sort { |x,y| x[3] <=> y[3] } # sort on 4th element
That's even better:
a.sort_by {|row| row[3]}
The reason that #sort_by is better than #sort is described in the
documentation. In short (IIRC) it's because it caches the key values
for each row (performing the block only once for each row) and uses
those to sort, rather than invoking the block for every unique pair it
has to compare.
Yep. Plus, it's shorter to type, which was the main advantage I wanted to
point out here.
A downside, however, is the inability to specify something like a
reverse sort. (Although for that case you can just reverse the array
afterwards.)
Actually, does anyone have a compelling example where #sort produce a
result (which is reasonable) which #sort_by cannot? (By 'reasonable' I
mean that something like a.sort{ |x,y| x[3] <=> y[7] } does something
impossible for #sort_by, but probably would produce erratic results,
given no way of knowing in which order the pairs come.)
The only one that I can think of at the moment is the one where there is
no proper comparision op defined. This is a made up example:
NoMethodError: undefined method `<=>' for #<struct El foo=nil, bar=nil>
from (irb):3
=> [#<struct El foo=6, bar=7>, #<struct El foo=5, bar=9>, #<struct El
foo=4, bar=8>, #<struct El foo=8, bar=9>, #<struct El foo=8, bar=7>,
#<struct El
[QUOTE="# said:
values.sort {|a,b| c = a.foo <=> b.foo; c == 0 ? a.bar <=> b.bar : c}
[/QUOTE]
=> [#<struct El foo=1, bar=2>, #<struct El foo=2, bar=2>, #<struct El
foo=3, bar=5>, #<struct El foo=4, bar=5>, #<struct El foo=4, bar=8>,
#<struct El
foo=5, bar=9>, #<struct El foo=6, bar=7>, #<struct El foo=8, bar=2>,
#<struct El foo=8, bar=7>, #<struct El foo=8, bar=9>]
You can do this with sort_by but you have to create new instances (Arrays
in this case), which might or might not be acceptable depending on the
circumstances:
values.sort_by {|x| [x.foo, x.bar]}
=> [#<struct El foo=1, bar=2>, #<struct El foo=2, bar=2>, #<struct El
foo=3, bar=5>, #<struct El foo=4, bar=5>, #<struct El foo=4, bar=8>,
#<struct El
foo=5, bar=9>, #<struct El foo=6, bar=7>, #<struct El foo=8, bar=2>,
#<struct El foo=8, bar=7>, #<struct El foo=8, bar=9>]
I guess most real world cases can be covered by #sort_by.
Kind regards
robert