idiom for Hash like map...

M

Mikel Lindsaar

class Fruit
attr_accessor :name, :price
def initialize(args)
@name = args[:name]
@price = args[:price]
end
end

array = [ Fruit.new:)name => "apple", :price => 2),
Fruit.new:)name => "grape", :price => 20),
Fruit.new:)name => "pear", :price => 200) ]

hash = Hash.new

array.each do |obj|
hash.merge!({obj.name => obj.price})
end

hash.inspect # => "{\"grape\"=>20, \"apple\"=>2, \"pear\"=>200}"



The "hash = {} / hash.merge!" thing bugs me... what is the better way?


Mikel
 
D

David A. Black

Hi --

class Fruit
attr_accessor :name, :price
def initialize(args)
@name = args[:name]
@price = args[:price]
end
end

array = [ Fruit.new:)name => "apple", :price => 2),
Fruit.new:)name => "grape", :price => 20),
Fruit.new:)name => "pear", :price => 200) ]

hash = Hash.new

array.each do |obj|
hash.merge!({obj.name => obj.price})
end

hash.inspect # => "{\"grape\"=>20, \"apple\"=>2, \"pear\"=>200}"



The "hash = {} / hash.merge!" thing bugs me... what is the better way?

You might like this better:

hash = Hash[*array.map {|e| [e.name, e.price] }.flatten ]

or this:

hash = array.inject({}) {|h, fruit| h[fruit.name] = fruit.price; h }


David

--
Rails training from David A. Black and Ruby Power and Light:
INTRO TO RAILS June 9-12 Berlin
ADVANCING WITH RAILS June 16-19 Berlin
INTRO TO RAILS June 24-27 London (Skills Matter)
See http://www.rubypal.com for details and updates!
 
R

Rob Biedenharn

class Fruit
attr_accessor :name, :price
def initialize(args)
@name = args[:name]
@price = args[:price]
end
end

array = [ Fruit.new:)name => "apple", :price => 2),
Fruit.new:)name => "grape", :price => 20),
Fruit.new:)name => "pear", :price => 200) ]

hash = Hash.new

array.each do |obj|
hash.merge!({obj.name => obj.price})
end

hash.inspect # => "{\"grape\"=>20, \"apple\"=>2, \"pear\"=>200}"


The "hash = {} / hash.merge!" thing bugs me... what is the better way?

Mikel


If your general question is something like, "How can I take an array
of objects and turn it into a key/value hash where the key and the
value are based on methods on each object?"

Then you could do something like:

irb> Hash[*array.map{|f|[f.name,f.price]}.flatten]
=> {"grape"=>20, "apple"=>2, "pear"=>200}

If any of the attributes (methods) return Arrays, the flatten will not
produce the result that you want. Also, if the 'name's aren't unique,
the hash will have fewer pairs that the array had entries.

-Rob

Rob Biedenharn http://agileconsultingllc.com
(e-mail address removed)
 
A

ara.t.howard

class Fruit
attr_accessor :name, :price
def initialize(args)
@name = args[:name]
@price = args[:price]
end
end

array = [ Fruit.new:)name => "apple", :price => 2),
Fruit.new:)name => "grape", :price => 20),
Fruit.new:)name => "pear", :price => 200) ]

hash = Hash.new

array.each do |obj|
hash.merge!({obj.name => obj.price})
end

hash.inspect # => "{\"grape\"=>20, \"apple\"=>2, \"pear\"=>200}"



The "hash = {} / hash.merge!" thing bugs me... what is the better way?

class Fruit
def to_hash
{ :name => name, :price => price }
end
end

array.each{|fruit| hash.update fruit.to_hash}

a @ http://codeforpeople.com/
 
M

Mikel Lindsaar

On May 7, 2008, at 5:18 AM, Mikel Lindsaar wrote:
class Fruit
def to_hash
{ :name => name, :price => price }
end
end
array.each{|fruit| hash.update fruit.to_hash}

Hmm.. put the responsibility back into the class. I guess that
actually makes the most sense.

Thanks David and Rob for your suggestions, totally hadn't considered
those idioms.

Mikel
 
R

Robert Klemme

2008/5/8 Mikel Lindsaar said:
Hmm.. put the responsibility back into the class. I guess that
actually makes the most sense.

But this approach has the drawback to create a lot of temporary
instances that are thrown away immediately.

Of course I do not know your use case but if I was building an index
I'd rather insert the object as value instead of a field. Just for
the fun of it:

irb(main):001:0> Fruit = Struct.new :name, :price
=> Fruit
irb(main):002:0> fruits = [Fruit.new("foo",1),Fruit.new("bar",2)]
=> [#<struct Fruit name="foo", price=1>, #<struct Fruit name="bar", price=2>]
irb(main):005:0> indexes = Hash.new {|h,k| h[k]= Hash.new(&h.default_proc)}
=> {}
irb(main):006:0> fruits.each {|f| f.members.each {|m| indexes[m][f[m]]=f}}
=> [#<struct Fruit name="foo", price=1>, #<struct Fruit name="bar", price=2>]
irb(main):008:0> require 'pp'
=> true
irb(main):009:0> pp indexes
{"name"=>
{"foo"=>#<struct Fruit name="foo", price=1>,
"bar"=>#<struct Fruit name="bar", price=2>},
"price"=>
{1=>#<struct Fruit name="foo", price=1>,
2=>#<struct Fruit name="bar", price=2>}}
=> nil

Cheers

robert
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top