Attempting to change the value in a 2 dimensional array in ruby changes every value, and I don't know a workaround

Viewed 19

I'm attempting to make something that requires a two dimensional array in order to choose what to display on screen, but I've noticed some weirdness and I'm not sure how to get around it. Creating a 2d array via Array.new causes any attempt to set a value in 1 nested array to set it in all nested arrays.

a = Array.new(3, Array.new(3, 0)) #=> [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
a[1][1] = 1                       #=> 1
a                                 #=> [[0, 1, 0], [0, 1, 0], [0, 1, 0]]

However, making the same array by specifying every value doesnt have this same behaviour (and is how I was expecting it to work)

b = [[0,0,0],[0,0,0],[0,0,0]]     #=> [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
b[1][1] = 1                       #=> 1
b                                 #=> [[0, 0, 0], [0, 1, 0], [0, 0, 0]]

I'm not exactly sure why this happens, and I can't seem to find a better way to make this array as specifying each individual value would take forever. Why is this happening, and how can I avoid it in future?

1 Answers

You have created an array with three references to the same object. Thus when you change one, you change them all, because they're all the same.

We can see this with #object_id.

Array.new(3, Array.new(3, 0)).map(&:object_id)
# => [70368430794940, 70368430794940, 70368430794940]

Using the block form of Array#new will resolve this.

Array.new(3) { Array.new(3, 0) }.map(&:object_id)
# => [70368431982020, 70368431982000, 70368431981980]
Related