3x3 Array of int, changing one value affects others

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.

On Tue, Sep 28, 2010 at 10:47 AM, Williams Williams
[email protected] 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.

That constructor of Array takes the second argument, and places it
(the same object) in all positions of the array.
So when you modify that object, you see the modification in all
positions. If you want a different object in each position, try the
block form:

irb(main):001:0> a = Array.new(3,Array.new(3,0))
=> [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
irb(main):002:0> a[0].object_id
=> -609376368
irb(main):003:0> a[1].object_id
=> -609376368
irb(main):004:0> a[2].object_id
=> -609376368

Same object id

irb(main):005:0> a = Array.new(3) {Array.new(3,0)}
=> [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
irb(main):006:0> a[0].object_id
=> -609423628
irb(main):007:0> a[1].object_id
=> -609423638
irb(main):010:0> a[2].object_id
=> -609423678

different object id

Jesus.

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

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs