Ruby 2D array assignment gotcha
Recently I came across an interesting ruby Array class gotcha.
As usual, I will start with the example.
Let us instantiate a 2D array.
arr = Array.new(3, Array.new(3, 0))
Now, we can assign a value to a cell in the matrix
arr[1][1] = 1
puts arr
# [[0, 1, 0], [0, 1, 0], [0, 1, 0]]
Huh! (scratches head)
Let us try without using Array.new
arr_2 = []
3.times { arr_2 << Array.new(3, 0)}
arr_2[1][1] = 1
puts arr_2
# [[0, 0, 0], [0, 1, 0], [0, 0, 0]]
This looks ok.
Time to hit the docs
Note that the second argument populates the array with references to the same object. Therefore, it is only recommended in cases when you need to instantiate arrays with natively immutable objects such as Symbols, numbers, true or false.
To declutter our initial arr
instantiation, the row was initialized only once and used multiple times.
row = Array.new(3, 0)
arr = Array.new(3, row)
We can check some more
arr = Array.new(3, Array.new(3, 0))
arr[0].equal? arr[1] # will return true
arr[0].equal? arr[2] # will return true
arr_2 = []
3.times { arr_2 << Array.new(3, 0)}
arr_2[0].equal? arr_2[1] # will return false
arr_2[0].equal? arr_2[2] # will return false
There is a safer alternative available. We can use blocks
arr = Array.new(3) { Array.new(3, 0) }
arr[0].equal? arr[1] # will return false
arr[0].equal? arr[2] # will return false
arr[1][1] = 1
puts arr
# [[0, 0, 0], [0, 1, 0], [0, 0, 0]]
Comments