Be careful with your Array initializers
Posted by admin, Thu Aug 23 07:59:28 UTC 2007
This one had me going for couple of hours today. I wanted to segregate some data into “buckets”. So I initialized my array of arrays (buckets), and then proceeded to add stuff to the individual buckets. But my unit test was failing, because, for a system of 10 buckets, and me adding 1 thing, I always got back 10 things. Weird. But look at this:
$ irb
irb(main):001:0> foo = Array.new(10, [])
=> [[], [], [], [], [], [], [], [], [], []]
irb(main):003:0> foo[0] << 1
=> [1]
irb(main):004:0> foo
=> [[1], [1], [1], [1], [1], [1], [1], [1], [1], [1]]
irb(main):005:0>
WTF? So, that array that I initialized my buckets with? The same array. Add to one, add to all. Grrr.
Now, I know this is in the PickAxe book, in the RDocs for Array.new… But I never read that far, ok?
So, for the confused, the correct answer is to use a block initializer like so:
irb(main):008:0> foo = Array.new(10) { [] }
=> [[], [], [], [], [], [], [], [], [], []]
irb(main):009:0> foo[0] << 1
=> [1]
irb(main):010:0> foo
=> [[1], [], [], [], [], [], [], [], [], []]
irb(main):011:0>