How can I initialize an Array inside a Hash in Rub

2019-02-04 01:26发布

问题:

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?

回答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:

  1. 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.

  2. 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 cause some_key to be inserted in the hash.



回答2:

Try this:

@my_hash = Hash.new { |h, k| h[k] = Array.new }


回答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.



标签: ruby arrays hash