Hash of arrays - whats going on?

I want a hash, where the values of the keys are arrays, eg

h = Hash.new
h.default = []

h[‘foo’] << 10
h[foo’] << 20
h[‘bar’] << 23
h[‘bar’] << 33

I thought this would give me

{ ‘foo’ => [20 30],
‘bar’ => [23, 33] }

but it doesn’t - it seems to put the same array in the value of each
key. Some googling revealed I need to create my hash like:

h = Hash.new { |hash, key| hash[key] = [] }

So my problem is solved, but why do you have to do it like this? At
the risk of answering my own question, is it because the block is re-
executed everytime you access a non existent key, creating a brand new
array object, while the first way, it just initialises the value to
the same array each time?

Thanks,

Stephen.

On Fri, Jul 20, 2007, stephen O’D wrote:

So my problem is solved, but why do you have to do it like this? At
the risk of answering my own question, is it because the block is re-
executed everytime you access a non existent key, creating a brand new
array object, while the first way, it just initialises the value to
the same array each time?

The default value you provide is a reference… in this case, you say
“use this array as the default value”, not “use an empty array as a
default value”. To see what I mean, try this:

empty_ary = []
h = Hash.new
h.default = empty_ary

h['foo'] << 10
puts empty_ary.size

h[foo'] << 20
puts empty_ary.size

h['bar'] << 23
puts empty_ary.size

h['bar'] << 33
puts empty_ary.size

That should show you what’s happening.

Ben

default just lets you return a default value if the request key
doesn’t exist, it’s not supposed to change the state of the hash.

What was happening is an array was presented to you when you called
h[‘foo’], and you were putting a value in it, but the array was never
saved to a variable, so it went away.

With the original code try the following code, it may help you
understand:
h[‘foo’] << 10
puts h.length
h[foo’] << 20
puts h.length