Creating an Array of Hashes in Ruby
I just made a simple mistake which I figure would be good share with anybody new-ish to Ruby. I wrote the following code to create an array of hashes and fill in some values. Can you guess what the output is?
#!/usr/bin/env ruby
testArray = Array.new(5, Hash.new)
0.upto(4) do |i|
testArray[i][:value] = i
end
0.upto(4) do |i|
puts testArray[i][:value]
end
If you said:
4
4
4
4
4
then you are right. The problem with this code is the Hash.new only creates one hash. And then each element in the array is a reference to that hash. So when any value is changed, all are changed. Instead, moving the hash creation inside the loop fixes everything:
#!/usr/bin/env ruby
testArray = Array.new(5, 0)
0.upto(4) do |i|
testArray[i] = Hash.new
testArray[i][:value] = i
end
0.upto(4) do |i|
puts testArray[i][:value]
end
outputs:
0
1
2
3
4


Comment by John McNulty on 15 April 2009:
I am new to Ruby so I spent 4 hours trying to figure this out. I found your post and had everything working in 5 minutes. Thank you!
Comment by Anonymous on 12 May 2009:
I kind of prefer the loops this way:
(0..4).each do { |i|
puts testArray[i][:value]
}
…they are just easier to read.
The bit about having to initialize every hash in the array was also nice for this noob to learn.
Comment by joe on 7 October 2009:
Thanks for the fix. Was wondering why my array values kept getting overwritten.
Comment by aashish on 19 February 2010:
thanks a lot
Comment by Sidy Diop on 2 October 2010:
I would just do:
===========
testArray = Array.new
(0..4).each do |i|
testArray < i }
end
(0..4).each do |i|
puts testArray[i][:value]
end
You could also inspect your data structure to make sure you created what you wanted:
puts testArray.inspect
===========
Comment by Chris on 7 November 2011:
Thanks! I was about to lose my mind until I saw this article.