DaniG2k DaniG2k - 1 year ago 68
Ruby Question

Bug with Ruby arrays?

I am using Ruby 2.3.1 and I cannot tell if I've encountered a bug or if this is intended behavior.

If you create an NxN matrix by making nested arrays, as such:

matrix = [[0]*5]*5

and then set the elements on the diagonals, as such:

(0..4).each {|i| matrix[i][i] = i}

this ends up affecting every column in every row:

[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4]

Is this intended behavior?

P.S. I do not want to use Ruby's Matrix library, but would rather work with plain arrays.

Thanks in advance :)

Answer Source

In Ruby, arrays are, behind the scenes, objects of type array, which can contain primitive types and references to other objects. Now, this last bit is important - the array doesn't contain the object itself, but instead a pointer to it, which is interpreted as necessary when the programmer asks for it.

So the OP's original initialization code

matrix = [[0]*5]*5

Really creates a single array object containing 5 0s, and then copies the pointer to it 5 times. This also happens when you do

matrix = Array.new(5, Array.new(5, 0))

for precisely the same reason. So, as posted in the comments, the idiomatically correct Ruby way to create an array of 5 different array objects is

matrix = Array.new(5){Array.new(5, 0)}

Which yields a single array that contains pointers to 5 different array objects, preventing the issue encountered by the OP. Full documentation on the behaviour of Ruby arrays can be found at this finely-crafted link.