Something wrong with my hash of hash

I try to get a hash of hash to make some sort of counter (I have a set
of random pair and want to count the number of times they appear). I use
this code but even if I can access data, my hash seems empty (so each
and the others don’t work):

h = Hash.new(Hash.new(0))
h[“a”][“b”] += 1
h[“a”][“b”] += 1
h[“a”][“c”] += 1
p h[“a”][“b”] => 2
p h[“a”][“c”] => 1
p h.class => Hash
p h[“a”].class => Hash
p h[“a”][“b”].class => Fixnum
p h => {}

What’s wrong?

Lars

Changing declaration by

h = Hash.new {|h,k| h[k] = Hash.new(0) }

makes things ok. What are the difference beetween the two declaration?

Lars

[email protected] wrote:

h[“a”][“c”] += 1
Lars
Try this definition:

h = Hash.new { |h, k|
h[k] = Hash.new(0)
}

It will actually modify ‘h’ rather than simply returning and modifying
the default value.

Gennady.

On 10/29/07, Lars T. [email protected] wrote:

p h[“a”][“b”] => 2
p h[“a”][“c”] => 1
p h.class => Hash
p h[“a”].class => Hash
p h[“a”][“b”].class => Fixnum
p h => {}

What’s wrong?

You’re using the wrong form of Hash.new for this use case.

Hash.new(default)

gives you a hash which simply returns default from [key] when key
doesn’t exist, it leaves the hash itself alone.

You need to use a block

h = Hash.new {|h, k| h[k] = Hash.new(0)}
h[“a”][“b”] += 1
h[“a”][“b”] += 1
h[“a”][“c”] += 1
h[“a”][“b”] # => 2
h[“a”][“c”] # => 1
h.class # => Hash
h # => {“a”=>{“b”=>2, “c”=>1}}

Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

Lars T. wrote:

h = Hash.new(Hash.new(0))
Changing declaration by
h = Hash.new {|h,k| h[k] = Hash.new(0) }
makes things ok. What are the difference beetween the two declaration?

There are two differences:
First: The first version executes “Hash.new(0)” once (before the outer
Hash.new is called, since parameters are evaluated before the actual
method
call (obviously)) and stores the result as the default value. This means
that
if you do something like h[:foo][:chunky] = “bacon” and h[:foo] has not
been
assigned before, you will actually change the default value, so h[:bar]
[:chunky] will also be “bacon”. The second version just stores the block
and
executes it everytime a key that hasn’t been assigned before is
accessed.

Second: The second version has “h[k] =” in it, so it will not only
return the
newly created hash, it will also store it in the outer hash. The first
version won’t do that, which means that h will always appear as empty
until
you do any actual assignments to it.

HTH,
Sebastian

Sebastian H. wrote:

There are two differences:
[…]

Thanks all of you guys and especially Sebastian for the explanations.

Lars