0
a = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
b = []
row = []
3.times { row << 0 }
3.times { b << row }

p a #=> [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
p b #=> [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
p a == b                         #=> true
p (a[1][1] = 1) == (b[1][1] = 1) #=> true

# and yet ...
a[1][1] = 1
b[1][1] = 1
p a #=> [[0, 0, 0], [0, 1, 0], [0, 0, 0]]
p b #=> [[0, 1, 0], [0, 1, 0], [0, 1, 0]]

With this code, I'd expect the modified b to be the same as the modified a, but instead, the second element of each nested array is modified.

What am I missing? Why do a[1][1] = 1 and b[1][1] = 1 produce different results?

wilcro
  • 143
  • 9

1 Answers1

3

The line 3.times { b << row } adds 3 references to the same array to b, so modifying it once changes it three times in the array.

Try updating this to dup the row as you push it into b, i.e. 3.times { b << row.dup }.

(As I'm typing I'm seeing @mudasobwa beat me to it in a comment :) )

This approach will ensure b is filled with three unique arrays, rather than the same one three times.

If you're unsure, you can check the object_id, i.e. b.map(&:object_id) - at present, these will all be the same.

mikej
  • 65,295
  • 17
  • 152
  • 131
SRack
  • 11,495
  • 5
  • 47
  • 60