This question already has an answer here:
I was adding items to a Hash key. I was expecting to get a structure like this:
{
'a' : [1],
'b' : [2, 3, 4]
}
I used an Array to initialize the Hash.
irb> hash = Hash.new([])
=> {}
Then started using it:
irb> hash['a'] << 1
=> [1]
irb> hash['b'] << 2
=> [1, 2]
But it turns out:
irb> hash
=> {}
This is exactly the behavior that you would expect to see.
You never add anything to the
Hash
, therefore theHash
is completely empty. When you look up a key, that key will never exist, therefore it returns the default value, which you have specified to be anArray
.So, you look up the key
'a'
, which doesn't exist, and thus returns theArray
you specified as the default value. Then, you call<<
on thatArray
, which appends a value (1
) to it.Next, you look up the key
'b'
, which also doesn't exist, and thus returns theArray
you specified as the default value, which now contains the element1
you added earlier. Then, you call<<
on thatArray
, appending the value2
to it.You end up with a
Hash
that is still empty, since you never added anything to it. The default value of theHash
is now an array containing the values1
and2
.The output you are seeing is because IRb always prints the result of the last expression that was evaluated. The last expression in your example is calling
<<
on theArray
.<<
returns its receiver, which then is the return value of the entire expression and thus what IRb prints out.hash['a'] << 1
andhash['b'] << 2
isn't correct syntax for creating a key/value pair. You have to use=
for that:That should give you the hash
{'a' : [1], 'b' : [2]}
The constructor you used stores
[]
as the default value to return when accessing keys that are unknown. SinceArray#<<
modifies its receiver in place this initially empty array grows.To explain in more detail:
When you do
hash['a'] << 1
this is what happens:hash
looks to see if there is a key named'a'
Hash.new([])
it does have such a value,[]
and it returns that.[] << 1
is evaluated and this means that hash now stores[1]
as the value to return when a previously unencountered key is requested.If what you want is to store the key value pair instead use the third form of the constructor with a block:
Try the following instead:
The reason you got your unexpected results is that you specified an empty array as default value, but the same array is used; no copy is done. The right way is to initialize the value with a new empty array, as in my code.