On Tuesday 28 September 2010, Williams Williams wrote:
|ruby-1.9.2-head > a = Array.new(3, Array.new(3, 0))
| => [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
|ruby-1.9.2-head > a[0][2] = 1
| => 1
|ruby-1.9.2-head > a
| => [[0, 0, 1], [0, 0, 1], [0, 0, 1]]
|
|If the values aren’t all 0s, a[0][2] behaves correctly. Am I doing
|something wrong? Thanks.
Array.new(size, obj) doesn’t work the way you think. It creates an array
with
size elements, where each element is the same object. By same object,
I
don’t mean different objects equal to each other, but one single object
(you
can see this looking at the object_id of the sub-arrays). So, it should
be no
wonder that modifying one of the elements also changes the others. If
you want
to create an array containing three different arrays [0,0,0], you need
to use
the block form of Array.new:
Array.new(3){|i| Array.new(3,0)}
This constructor creates an array of the given size, then calls the
block for
each index of the array and stores in that index the value returned by
the
block. Different from your code, now the array contains three arrays
with
different identities, all with the same contents. This is because every
time
the block is called, it returns a new array.
To be more clear, your code has the same results as:
create an array of size 3 filled with nil
a = Array.new(3)
create the subarray
subarray = Array.new(3,0)
#store the same subarray in all the three entries of the array
a[0] = subarray
a[1] = subarray
a[2] = subarray
The code which works as you want, instead, produces the same as:
create an array of size 3 filled with nil
a = Array.new(3)
#store in the tree entries of the array three different arrays with
#the same contents
a[0] = Array.new(3,0)
a[1] = Array.new(3,0)
a[2] = Array.new(3,0)
Usually, you only use Array.new(size, obj) when obj is an immutable
object,
that is an object with no methods which modify it. Your use of
Array.new(3,0),
for instance, is correct because an Integer can’t be modified. The same
would
be true, for example, for symbols. If obj is a mutable object, like a
string,
an array or a hash (which all have methods which change the object
itself),
creating an array this way can lead to unexpected result, as you have
experienced yourself.
I hope this helps
Stefano