5

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?

Michael Z
  • 3,883
  • 10
  • 43
  • 57
  • possible duplicate of [Modifying the default hash value](http://stackoverflow.com/questions/9492889/modifying-the-default-hash-value) – mu is too short Mar 06 '12 at 20:16
  • I'm having trouble coming up with any reasonable scenario where what you want makes sense. Why do you expect `h[2]` to have the same value as `h[1]`. – Phrogz Mar 06 '12 at 20:16
  • Ooops, sorry I have edited my expected results. Nevertheless I have accepted answer already. – Michael Z Mar 06 '12 at 20:22
  • @MichaelZ OK, great; I'll delete the confusing edit from my answer. – Phrogz Mar 06 '12 at 20:23

2 Answers2

9

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

Phrogz
  • 296,393
  • 112
  • 651
  • 745
0

Why don't you just use an array for it if you were going to use numeric indexes for Hash anyways?

h = []
h<<:word1 
h<<:word2
h<<:word3
print h

To achieve your desired output:

h = []
h<<:word1 
h<<:word2
h<<[]
h[2]<<h[1]<<:word3
print h
gtr32x
  • 2,033
  • 4
  • 20
  • 32