"Wybo Dekker" <wybo / servalys.nl> schrieb im Newsbeitrag 
news:Pine.LNX.4.61.0602041523170.10213 / servalys.nl...
> On Sat, 4 Feb 2006, Robert Klemme wrote:
>
>> The easiest is probably to use sort_by.
>>
>> Thing = Struct.new(:name, :amount)
>> arr = [
>> Thing.new('John',10),
>> Thing.new('Anny',20),
>> ]
>>
>> p arr.sort_by {|x| x.name}
>> p arr.sort_by {|x| x.amount}
>
> this does not allow for more complex sorts, like on name *and* amount,
> does it?

It does: arr.sort_by {|x| [x.name, x.amount]} (depending on the precedence 
you want).  I believe, if you use Struct and want to order according to 
field order then you might be able to just use sort() without arguments 
(alternatively sort_by {|x| x.to_a} - to_a is defined by Struct).

> I saw that it is also possible to give sort an argument instead of a
> block:
>
> require 'pp'
>
> Thing = Struct.new(:name, :amount)
> arr = [
>  Thing.new('John',80),
>  Thing.new('John',10),
>  Thing.new('John',30),
>  Thing.new('Anny',20),
>  Thing.new('Anny',10),
>  Thing.new('Anny',30),
>  Thing.new('Anny',15)
> ]
>
> def byname(a,b)     a.name <=> b.name end
> def byamount(a,b) a.amount <=> b.amount end
> def by_name_amount(a,b)
>  (a.name <=> b.name)*4 + (a.amount <=> b.amount)
> end
>
> [:byname,:byamount,:by_name_amount].each do |order|
>  puts "sort #{order}:"
>  pp arr.sort(&method(order))
> end
>
> But ri does not tell me that:
>
> -------------------------------------------------------- Enumerable#sort
>     enum.sort                     => array
>     enum.sort {| a, b | block }   => array
> ------------------------------------------------------------------------
>     Returns an array containing the items in _enum_ sorted, either
>     according to their own +<=>+ method, or by using the results of the
>     supplied block. The block should return -1, 0, or +1 depending on
>     the comparison between _a_ and _b_. As of Ruby 1.8, the method
>     +Enumerable#sort_by+ implements a built-in Schwartzian Transform,
>     useful when key computation or comparison is expensive..
>
>        %w(rhea kea flea).sort         #=> ["flea", "kea", "rhea"]
>        (1..10).sort {|a,b| b <=> a}   #=> [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]

Actually ri tells you that - because it's the block form.  Your methods are 
implicitely converted to blocks.  In that case I'd rather not use a method 
definition but rather do the more direct lambda / proc:

Thing::BYNAME = lambda {|a,b| a.name <=> b.name}
Thing::BYAMOUNT = lambda {|a,b| a.amount <=> b.amount}
....
arr.sort(&Thing::BYNAME)

You can as well define those constants in global scope but I felt they are 
more appropriately placed in Thing's scope because they refer exactly to 
Things.

Kind regards

    robert