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