JohnnyBeGood
JohnnyBeGood

Reputation: 177

Ruby update hash of hash strange behavior

I have created a hash of hash with the hour of the day being the key to a hash with id => zero.

For instance:

{0=>{1=>0, 2=>0, 3=>0, 4=>0}, 1=>{1=>0, 2=>0, 3=>0, 4=>0}, 
    2=>{1=>0, 2=>0, 3=>0, 4=>0}, 3=>{1=>0, 2=>0, 3=>0, 4=>0}, 
    4=>{1=>0, 2=>0, 3=>0, 4=>0}, 5=>{1=>0, 2=>0, 3=>0, 4=>0}, 
    6=>{1=>0, 2=>0, 3=>0, 4=>0}, 7=>{1=>0, 2=>0, 3=>0, 4=>0}, 
    8=>{1=>0, 2=>0, 3=>0, 4=>0}, 9=>{1=>0, 2=>0, 3=>0, 4=>0}, 
    10=>{1=>0, 2=>0, 3=>0, 4=>0}, 11=>{1=>0, 2=>0, 3=>0, 4=>0}, 
    12=>{1=>0, 2=>0, 3=>0, 4=>0}, 13=>{1=>0, 2=>0, 3=>0, 4=>0}, 
    14=>{1=>0, 2=>0, 3=>0, 4=>0}, 15=>{1=>0, 2=>0, 3=>0, 4=>0}, 
    16=>{1=>0, 2=>0, 3=>0, 4=>0}, 17=>{1=>0, 2=>0, 3=>0, 4=>0}, 
    18=>{1=>0, 2=>0, 3=>0, 4=>0}, 19=>{1=>0, 2=>0, 3=>0, 4=>0}, 
    20=>{1=>0, 2=>0, 3=>0, 4=>0}, 21=>{1=>0, 2=>0, 3=>0, 4=>0}, 
    22=>{1=>0, 2=>0, 3=>0, 4=>0},  23=>{1=>0, 2=>0, 3=>0, 4=>0}}

I used this code to create them:

hour_hash = {}
count = (1..4).inject({}) {|m,e| m[e]=0;m}
(0..23).each do |i|
    hour_hash[i]=count
end

When I try to update the element in one of the hash, like so:

hour_hash[0][3] += 1

The entire hash get updated:

{0=>{1=>0, 2=>0, 3=>1, 4=>0}, 1=>{1=>0, 2=>0, 3=>1, 4=>0}, 
 2=>{1=>0, 2=>0, 3=>1, 4=>0}, 3=>{1=>0, 2=>0, 3=>1, 4=>0}, 
 4=>{1=>0, 2=>0, 3=>1, 4=>0}, 5=>{1=>0, 2=>0, 3=>1, 4=>0}, 
 6=>{1=>0, 2=>0, 3=>1, 4=>0}, 7=>{1=>0, 2=>0, 3=>1, 4=>0}, 
 8=>{1=>0, 2=>0, 3=>1, 4=>0}, 9=>{1=>0, 2=>0, 3=>1, 4=>0}, 
 10=>{1=>0, 2=>0, 3=>1, 4=>0}, 11=>{1=>0, 2=>0, 3=>1, 4=>0}, 
 12=>{1=>0, 2=>0, 3=>1, 4=>0}, 13=>{1=>0, 2=>0, 3=>1, 4=>0}, 
 14=>{1=>0, 2=>0, 3=>1, 4=>0}, 15=>{1=>0, 2=>0, 3=>1, 4=>0}, 
 16=>{1=>0, 2=>0, 3=>1, 4=>0}, 17=>{1=>0, 2=>0, 3=>1, 4=>0}, 
 18=>{1=>0, 2=>0, 3=>1, 4=>0}, 19=>{1=>0, 2=>0, 3=>1, 4=>0}, 
 20=>{1=>0, 2=>0, 3=>1, 4=>0}, 21=>{1=>0, 2=>0, 3=>1, 4=>0}, 
 22=>{1=>0, 2=>0, 3=>1, 4=>0}, 23=>{1=>0, 2=>0, 3=>1, 4=>0}}

Can someone enlighten me? I should be able to access a single element in the hash, like hash[x][y], right? Thank you very much for your help!

Upvotes: 0

Views: 72

Answers (2)

Jacob Brown
Jacob Brown

Reputation: 7561

I think you could use Hash's default values block here:

hour_hash = Hash.new {|h, k| h[k] = {1=>0, 2=>0, 3=>0, 4=>0 } }

If you just need to look up values, you could stop here. If you need "empty" values for 0..23 you could add:

(0..23).each {|x| hour_hash[x] }

And use it like:

hour_hash[0][3] += 1

Upvotes: 1

sawa
sawa

Reputation: 168101

hour_hash = (0..23).each_with_object({}) do |i, h|
  h[i] = (1..4).each_with_object({}){|j, h| h[j] = 0}
end

hour_hash[0][3] += 1

hour_hash # =>

{0=>{1=>0, 2=>0, 3=>1, 4=>0}, 1=>{1=>0, 2=>0, 3=>0, 4=>0}, 2=>{1=>0, 2=>0, 3=>0, 4=>0}, 3=>{1=>0, 2=>0, 3=>0, 4=>0}, 4=>{1=>0, 2=>0, 3=>0, 4=>0}, 5=>{1=>0, 2=>0, 3=>0, 4=>0}, 6=>{1=>0, 2=>0, 3=>0, 4=>0}, 7=>{1=>0, 2=>0, 3=>0, 4=>0}, 8=>{1=>0, 2=>0, 3=>0, 4=>0}, 9=>{1=>0, 2=>0, 3=>0, 4=>0}, 10=>{1=>0, 2=>0, 3=>0, 4=>0}, 11=>{1=>0, 2=>0, 3=>0, 4=>0}, 12=>{1=>0, 2=>0, 3=>0, 4=>0}, 13=>{1=>0, 2=>0, 3=>0, 4=>0}, 14=>{1=>0, 2=>0, 3=>0, 4=>0}, 15=>{1=>0, 2=>0, 3=>0, 4=>0}, 16=>{1=>0, 2=>0, 3=>0, 4=>0}, 17=>{1=>0, 2=>0, 3=>0, 4=>0}, 18=>{1=>0, 2=>0, 3=>0, 4=>0}, 19=>{1=>0, 2=>0, 3=>0, 4=>0}, 20=>{1=>0, 2=>0, 3=>0, 4=>0}, 21=>{1=>0, 2=>0, 3=>0, 4=>0}, 22=>{1=>0, 2=>0, 3=>0, 4=>0}, 23=>{1=>0, 2=>0, 3=>0, 4=>0}}

Upvotes: 1

Related Questions