From: Ross Bamford Date: 2006-02-04T22:15:48+09:00 Subject: Re: how to vary sort's block? On Sat, 2006-02-04 at 19:40 +0900, 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? > Yes, see below: > #!/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) > ] # Replace rest of the code with: orders = { :byname => lambda { |a,b| a.name <=> b.name }, :byamount => lambda { |a,b| a.amount <=> b.amount } } order = :byname if blk = orders[order] puts "sorted #{order}:" arr.sort(&blk).each { |a| a.list } else raise "illegal order" end __END__ This would be my first implementation I think, I like dispatch table type stuff. Be careful what you enclose with all those blocks, though. An alternative idea might be (replacing the code I show above): require 'curry' # Have to download this, see bottom sort_proc = lambda { |msg,a,b| a.send(msg) <=> b.send(msg) } by_name = sort_proc.curry(:name) by_amount = sort_proc.curry(:amount) puts "sorted name:" arr.sort(&by_name).each { |a| a.list } >> # => sorted name: >> # => Anny 20 >> # => John 10 puts "sorted amount:" arr.sort(&by_amount).each { |a| a.list } >> # => sorted amount: >> # => John 10 >> # => Anny 20 (You could curry on the fly of course depending on the sort criteria, it's reasonably low-overhead). Does it show I've been searching for an opportunity to use currying since I did that quiz entry? ;D (Curry: http://www.ruby-talk.org/cgi-bin/scat.rb/ruby/ruby-talk/177343 ) -- Ross Bamford - rosco@roscopeco.REMOVE.co.uk