[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

idiom for Hash like map...

Mikel Lindsaar

5/7/2008 11:19:00 AM

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

5 Answers

David A. Black

5/7/2008 11:39:00 AM

0

Hi --

On Wed, 7 May 2008, Mikel Lindsaar wrote:

> 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.r... for details and updates!

Rob Biedenharn

5/7/2008 11:54:00 AM

0

On May 7, 2008, at 7:18 AM, Mikel Lindsaar wrote:

> 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://agileconsult...
Rob@AgileConsultingLLC.com


ara.t.howard

5/7/2008 2:52:00 PM

0


On May 7, 2008, at 5:18 AM, Mikel Lindsaar wrote:
> 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://codeforp...
--
we can deny everything, except that we have the possibility of being
better. simply reflect on that.
h.h. the 14th dalai lama




Mikel Lindsaar

5/8/2008 3:18:00 AM

0

On Thu, May 8, 2008 at 12:51 AM, ara.t.howard <ara.t.howard@gmail.com> wrote:
> 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

Robert Klemme

5/8/2008 3:17:00 PM

0

2008/5/8 Mikel Lindsaar <raasdnil@gmail.com>:
> On Thu, May 8, 2008 at 12:51 AM, ara.t.howard <ara.t.howard@gmail.com> wrote:
>> 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.

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

--
use.inject do |as, often| as.you_can - without end