Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I initialize an Array inside a Hash in Ruby [duplicate]

Tags:

arrays

ruby

hash

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?

like image 472
jfanals Avatar asked Dec 10 '10 14:12

jfanals


2 Answers

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

like image 195
sepp2k Avatar answered Sep 28 '22 15:09

sepp2k


Try this:

@my_hash = Hash.new { |h, k| h[k] = Array.new } 
like image 44
Incidently Avatar answered Sep 28 '22 13:09

Incidently