Re: how to vary sort's block?



Wybo Dekker <wybo@xxxxxxxxxxx> 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

.



Relevant Pages

  • Re: BASIC - removing and replacing string characters
    ... Folderol wrote: ... DEF FNfoo ... This sort of thing is much easier being dumped into a byte ... array and then manipulated with indirection operators. ...
    (comp.sys.acorn.programmer)
  • how to vary sorts block?
    ... When I have an array of objects ... the sort in a hash with keys telling what I want to sort on? ... def initialize ... def byname ...
    (comp.lang.ruby)
  • Re: [SORT?] by x,y allowing x,y to be passed as parms
    ... and a couple of methods to sort array of pointers by any two fields. ... def initialize @list_of_CDs = Array.new end ...
    (comp.lang.ruby)
  • Re: how to vary sorts block?
    ... On Feb 4, 2006, at 4:40 AM, Wybo Dekker wrote: ... `name' and `amount') I want to be able to sort that array by either of ...
    (comp.lang.ruby)
  • Re: how to vary sorts block?
    ... the sort in a hash with keys telling what I want to sort on? ... def initialize ... class Array ... (You could curry on the fly of course depending on the sort criteria, ...
    (comp.lang.ruby)