DaniG2k DaniG2k - 3 months ago 22
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

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.