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?
 
> Btw, I would *not* put byamount and byname into Array.  If you want to do
> something general, then I'd do this:
> 
> module Enumerable
> def sort_field(*fields)
>  sort_by {|x| fields.map {|f| x.send f}}
>  end
> end
> 
> Then you can do
> 
> p arr.sort_field :name
> p arr.sort_field :amount

but this is really great, I can now even say:
   p arr.sort_field(:name,:amount)
Thanks!

> It might even be reasonable to replace the current implementation of sort_by
> with one that accepts either a list of symbols as arguments or a block.  I
> think this might have been proposed already.  Matz, any comment on this? Does
> this sound reasonable?

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]


-- 
Wybo