From: Ryan Leavengood Date: 2005-11-13T12:25:59+09:00 Subject: Re: Nested hash constructor confusion On 11/9/05, Ben Armstrong wrote: > Can anyone explain the following? Our "intuitive" solution (h1) to > creating a constructor for a hash nested within a hash did not work. It > was only after attempting a workaround (h3) and finding that it > performed very poorly that we Googled (h2) a correct solution. But it > is not obvious to us why this more complex constructor is required. > > # Unexpected result, h1 hash is empty. > h1=Hash.new(Hash.new(0)) # => {} > h1[1][2]='h1' # => "h1" > h1 # => {} When you pass an object to the Hash.new constructor, that object is used as the default value for keys that don't have values. But that object isn't really "in" the hashtable data structure, it is just associated with the object (i.e. a member variable): irb(main):001:0> h1=Hash.new(Hash.new(0)) => {} irb(main):002:0> h1[0].object_id => 22753180 irb(main):003:0> h1[1].object_id => 22753180 irb(main):004:0> h1[0][0] => 0 irb(main):005:0> h1[0][0]='foo' => "foo" irb(main):006:0> h1[0][0] => "foo" irb(main):007:0> h1 => {} > # Expected result, h2 hash contains nested hash. > h2=Hash.new{|hash,key| hash[key]=Hash.new(0)} # => {} > h2[1][2]='h2' # => "h2" > h2 # => {1=>{2=>"h2"}} Others have described why this works and is the proper solution. > # Expected result but expensive. > h3=Hash.new(Hash.new(0)) # => {} > temp=h3[1].dup # => {} > temp[2]='h3' # => "h3" > h3[1]=temp # => {2=>"h3"} > h3 # => {1=>{2=>"h3"}} This is expensive because you are pulling out the default value from the hashtable and duplicating it on each key operation then actually putting it into the hashtable data structure. As you know now from the above this is not the proper way to work with hashtables with dynamically created values. Ryan