inquisitive
inquisitive

Reputation: 3974

ruby hashes, why is the value getting overridden

Consider the following code snippet:

inner_hash =Hash.new
 trial_hash = Hash.new
inner_hash.merge!("i_key1"=>"value1")
inner_hash.merge!("i_key2"=>"value2")
puts "inner_hash #{inner_hash}"
trial_hash.merge!("o_key1"=>inner_hash)
puts "trial_hash #{trial_hash}"
inner_hash.clear
inner_hash.merge!("i_key1"=>"value3")
inner_hash.merge!("i_key2"=>"value4")
puts "inner_hash #{inner_hash}"
trial_hash.merge!("o_key2"=>inner_hash)
puts "trial_hash #{trial_hash}"

This is what it prints:

inner_hash {"i_key1"=>"value1", "i_key2"=>"value2"}
trial_hash {"o_key1"=>{"i_key1"=>"value1", "i_key2"=>"value2"}}
inner_hash {"i_key1"=>"value3", "i_key2"=>"value4"}
trial_hash {"o_key1"=>{"i_key1"=>"value3", "i_key2"=>"value4"}, "o_key2"=>{"i_key1"=>"value3", "i_key2"=>"value4"}}

Especially see the trial_hash printed in the last line. The value of key "o_key1" is a hash whose value should have been value1 and value2 but have been overwritten to value3 and value4. ideally the expected output should have been:

inner_hash {"i_key1"=>"value1", "i_key2"=>"value2"}
trial_hash {"o_key1"=>{"i_key1"=>"value1", "i_key2"=>"value2"}}
inner_hash {"i_key1"=>"value3", "i_key2"=>"value4"}
trial_hash {"o_key1"=>{"i_key1"=>"value1", "i_key2"=>"value2"}, "o_key2"=>{"i_key1"=>"value3", "i_key2"=>"value4"}}

Why is this behaviour observed. What wrong am I doing. Originally the question is very broad and uses loops, which for sample purpose here, i have removed and re-written some of the lines. Any help is greatly appreciated. Thanks

EDIT: The problem is solved when I replaced inner_hash.clear with inner_hash={}

Upvotes: 0

Views: 62

Answers (1)

Yu Hao
Yu Hao

Reputation: 122493

When you do:

trial_hash.merge!("o_key1"=>inner_hash)

a reference of inner_hash is made as the value. So whenever inner_hash changes, trial_hash["o_key1"] changes accordingly, because they are references to the same Hash object.

Check out their object_id, the same:

trial_hash["o_key1"].object_id
#=> 21676080
trial_hash["o_key2"].object_id
#=> 21676080
inner_hash.object_id
#=> 21676080

You could get your expected behavior if using clone:

trial_hash.merge!("o_key1"=>inner_hash.clone)

Upvotes: 1

Related Questions