Wybo Dekker <wybo / servalys.nl> 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