How can I initialize an Array inside a Hash in Ruby
Solution 1
@my_hash = Hash.new(Array.new)
This creates exactly one array object, which is returned every time a key is not found. Since you only ever mutate that array and never create a new one, all your keys map to the same array.
What you want to do is:
@my_hash = Hash.new {|h,k| h[k] = Array.new }
or simply
@my_hash = Hash.new {|h,k| h[k] = [] }
Passing a block to Hash.new
differs from simply passing an argument in 2 ways:
The block is executed every time a key is not found. Thus you'll get a new array each time. In the version with an argument, that argument is evaluated once (before
new
is called) and the result of that is returned every time.By doing
h[k] =
you actually insert the key into the hash. If you don't do this just accessing@my_hash[some_key]
won't actually causesome_key
to be inserted in the hash.
Solution 2
Try this:
@my_hash = Hash.new { |h, k| h[k] = Array.new }
Solution 3
The argument for Hash.new is for the default value for new hash keys, so when you pass it a reference that reference will be used for new hash keys. You're updating that reference when you call...
hash["key"].push "value"
You need to pass a new reference into the hash key before pushing values to it...
hash["key1"] = Array.new
hash["key1"].push "value1"
hash["key2"] = Array.new
hash["key2"].push "value2
You could try encapsulating this into a helper method as well.
jfanals
Updated on July 09, 2022Comments
-
jfanals almost 2 years
I am trying to initialize a Hash of Arrays such as
@my_hash = Hash.new(Array.new)
so that I can:
@my_hash["hello"].push("in the street") => ["in the street"] @my_hash["hello"].push("at home") => ["in the street", "at home"] @my_hash["hello"] =>["in the street", "at home"]
The problem is that any new hash key also return
["in the street", "at home"]
@my_hash["bye"] => ["in the street", "at home"] @my_hash["xxx"] => ["in the street", "at home"]
!!!???
What am I doing wrong what would be the correct way to initialize a Hash of Arrays?
-
mashe over 13 yearsThe one gotcha to be aware of here is that now even checking a key will create it, which may not be what you want. For this reason I sometimes create the Hash normally (with just {}), and then do the array-creation in the call, like
(@myhash["hello"] ||= []).push("in the street")
.