I tried the following in versions 1.8.* and 2.0.*. Output from console
given below.
--------------------------------------------
h = Hash.new([]) # Want default output to be a list
=> {}
h[‘a’] # I expect an empty list and I get it
=> []
h[‘a’].push(10) # Works as expected…
=> [10]
h[‘a’] # Ok… want to check if the key ‘a’ was set in the hash
=> [10]
h # This should not be an empty hash…Wow, what happened?
=> {}
h.has_key?(‘a’)
=> false
h[‘a’] = h[‘a’].push(100) # Ok, let me set things explicitly
=> [10, 100]
h # Is the following output expected?
=> {“a”=>[10, 100]}
---------------------------------------------
Note that h[‘a’] points to [10] even though the key ‘a’ does not exist
in the hash. More bizarre is when I set things explicitly, and push 100
to the list at the same time. Then the hash shows the key ‘a’ with [10,
100] as the value.
I understand why the key ‘a’ was not formed when I did h[‘a’].push(10).
What is inconsistent is that h[‘a’] kept pointing to [10] even though
h.has_key?(‘a’) is false
Is this an expected behavior? Can someone explain please.
Thanks
This is mentioned in the documentation of Hash.new:
When you do this:
h = Hash.new([])
That Array is the same Array for every key.
If you want a different Array every time, you need to use a block:
h = Hash.new { |hash,key| hash[key] = [] }
Hi Joel, you are absolutely correct, but that was not the issue.
My confusion is that after I did h[‘a’].push(10), Ruby did as expected
and gave me [10]. Next, I printed h[‘a’] and it gave me [10], again all
good. Now, I check for existence of the key ‘a’ in the hash but it does
not exist, even though h[‘a’] gives me [10].
Maybe my issue is somehow related to your explanation, but I cannot see
it. Any thoughts?
Thanks.
Anirban Bh wrote in post #1153287:
My confusion is that after I did h[‘a’].push(10), Ruby did as expected
and gave me [10]. Next, I printed h[‘a’] and it gave me [10], again all
good. Now, I check for existence of the key ‘a’ in the hash but it does
not exist, even though h[‘a’] gives me [10].
The explanation is that Ruby has not created a key when you do h[‘a’],
but has just returned the default value for a nonexistent key. (h[‘a’]
is a get, h[‘a’]= is a set)
In more detail, when you do
h = Hash.new []
h[‘a’].push 10
[10]
Because h does not contain any keys, h[‘a’] returns the default value,
[], and pushes 10 onto it.
If you check the default value:
h.default
[10]
You can see there are no keys:
h.keys
[]
h
{}
If you ask for another non-existent key, you get back the same default
value:
h[‘b’]
[10]
To assign ‘a’ as a key, you need to do
h[‘a’] = []
And then things work as you expect:
h[‘a’].push 10
[10]
h.keys
[“a”]
h
=> {“a”=>[10]}
Hope this helps,
Peter.
Thank you Peter, you cleared my confusion when you said:
“If you ask for another non-existent key, you get back the same default
value”,
and the fact that it is not [] but [10] ties back to Joel’s explanation.
Thanks guys.