Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Initializing a Hash with empty array unexpected behaviour [duplicate]

Tags:

ruby

hash

I want to initialize a Hash with an empty Array and for every new key push a certain value to that array.

Here's what I tried to do:

a = Hash.new([])
# => {} 
a[1] << "asd"
# => ["asd"]
a
# => {}

The expected output for a was {1 => ["asd"]} but that didn't happen. What am I missing here?

Ruby version:

ruby 2.0.0p598 (2014-11-13 revision 48408) [x86_64-linux]
like image 493
shivam Avatar asked Jan 30 '15 11:01

shivam


1 Answers

Just do

a = Hash.new { |h, k| h[k] = [] }
a[1] << "asd"
a # => {1=>["asd"]}

Read the below lines from the Hash::new documentation. It really explains why you didn't get the desired result.

new(obj) → new_hash

If obj is specified, this single object will be used for all default values.

new {|hash, key| block } → new_hash

If a block is specified, it will be called with the hash object and the key, and should return the default value. It is the block’s responsibility to store the value in the hash if required.

You can test by hand :

a = Hash.new([])
a[1].object_id # => 2160424560
a[2].object_id # => 2160424560

Now with the above style of Hash object creation, you can see every access to an unknown key, returning back the same default object. Now the other way, I meant block way :

b = Hash.new { |h, k| [] }
b[2].object_id # => 2168989980
b[1].object_id # => 2168933180

So, with the block form, every unknown key access, returning a new Array object.

like image 113
Arup Rakshit Avatar answered Sep 23 '22 06:09

Arup Rakshit