Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Append element in hash's key-array

See my Ruby code:

h=Hash.new([])
h[0]=:word1    
h[1]=h[1]<<:word2
h[2]=h[2]<<:word3
print "\nHash = "
print h

Output is:

Hash = {0=>:word1, 1=>[:word2, :word3], 2=>[:word2, :word3]}

I've expected to have

Hash = {0=>:word1, 1=>[:word2], 2=>[:word3]}

Why the second hash element(array) was appended?

How can I append just the 3rd hash's element with new array element?

like image 586
Michael Z Avatar asked Mar 06 '12 19:03

Michael Z


Video Answer


1 Answers

If you supply a single value as a parameter to Hash.new (e.g. Hash.new( [] ) that exact same object is used as the default value for every missing key. That's what you had, and that's what you don't want.

You could instead use the block form of Hash.new, where the block is invoked each time a missing key is requested:

irb(main):001:0> h = Hash.new{ [] }
#=> {}
irb(main):002:0> h[0] = :foo
#=> :foo
irb(main):003:0> h[1] << :bar
#=> [:bar]
irb(main):004:0> h
#=> {0=>:foo}

However, as we see above you get the value but it's not set as the value for that missing key. As you did above, you need to hard-set the value. Often, what you want instead is for the value to magically spring to life as the value of that key:

irb(main):005:0> h = Hash.new{ |h,k| h[k] = [] }
#=> {}
irb(main):006:0> h[0] = :foo
#=> :foo
irb(main):007:0> h[1] << :bar
#=> [:bar]
irb(main):008:0> h
#=> {0=>:foo, 1=>[:bar]}

Now not only do we get the brand new array back when we ask for a missing key, but this automatically populates our hash with the array so that you don't need to do h[1] = h[1] << :bar

like image 135
Phrogz Avatar answered Oct 09 '22 18:10

Phrogz