From: Robert Klemme Date: 2006-02-04T21:53:19+09:00 Subject: Re: how to vary sort's block? Wybo Dekker wrote: > When I have an array of objects (Thing's, say) with two properties > (say `name' and `amount') I want to be able to sort that array by > either of these properties, depending on circumstances (like the > value of the variable `order'). > > The script below is an example, and it works, but I don't like it. > I there a better way to do it, without an if..else construction? > > For example, would it be possible to put several {|a,b|...} blocks for > the sort in a hash with keys telling what I want to sort on? > > #!/usr/bin/ruby > > class Thing > attr_reader :name,:amount > > def initialize(name,amount) > @name,@amount = name,amount > end > > def list > puts ['',@name,@amount].join("\t") > end > end > > class Array > def byamount > self.sort { |a,b| a.amount <=> b.amount } > end > def byname > self.sort { |a,b| a.name <=> b.name } > end > end > > arr = [ > Thing.new('John',10), > Thing.new('Anny',20) > ] > > order = :byname > > puts "sorted #{order}:" > if order == :byname > arr.sort { |a,b| a.name <=> b.name }.each { |a| > a.list > # much more code may occur here... > } > elsif order == :byamount > arr.sort { |a,b| a.amount <=> b.amount }.each { |a| > a.list > # much more code may occur here... > } > else > raise "illegal order" > end 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} 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 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? Kind regards robert