On Thu, 9 Nov 2006, Friedrich D. wrote:
I can not remember having read about it before, however the following
happens here:
irb(main):015:0> arr = Array.new(3, Array.new)
[…]
irb(main):018:0> arr1 = Array.new(3)
[nil, nil, nil]
irb(main):019:0> 0.upto(2) {|i| arr1[i] = Array.new}
0
[…]
I’m not getting it. Is it supposed to work that way?
Yes. In your first call, ‘Array.new’ is evaluated ONCE before the call,
and hence all array members get initialised to use the SAME array.
In your second example, you call Array.new once per array index, to make
sure every array index gets its own array assigned to it.
There is a slightly simpler way to achieve your desired behaviour,
though:
irb(main):004:0> arr=Array.new(3) { Array.new }
=> [[], [], []]
irb(main):005:0> arr[0].push(1)
=> [1]
irb(main):006:0> arr
=> [[1], [], []]
In this case, you’d be passing in Array.new as a block - which gets
evaluated ONCE per value in the array you’re creating…
To make it a bit more apparent, see the difference between:
irb(main):011:0> i=0
=> 0
irb(main):012:0> Array.new(3,i+=1) # i+=1 gets evaluated ONCE
=> [1, 1, 1]
and
irb(main):013:0> i=0
=> 0
irb(main):014:0> Array.new(3) { i+=1 } # i+=1 gets evaluated once PER
array item
=> [1, 2, 3]
The difference simply being that in the first case, your initialiser
gets
evaluated just once immediately before calling Array.new; and in the
second case, Array.new calls your block once PER array item that gets
created…
Benedikt
ALLIANCE, n. In international politics, the union of two thieves who
have their hands so deeply inserted in each other’s pockets that
they cannot separately plunder a third.
(Ambrose Bierce, The Devil’s Dictionary)