From: Wybo Dekker Date: 2006-02-04T23:45:20+09:00 Subject: Re: how to vary sort's block? 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