The problem here is b = Array.new(3, []) uses the same object as the base value for all cells in the array:
b = Array.new(3, []) b[0].object_id
Therefore, when you use b[0].push , it adds an element to the "every" sub-array, because all of them, in fact, have the same array.
So why does b [0] + = ["value"] work? Well, looking at ruby ββdocuments:
ary + other_ary β new_ary
Concatenation - returns a new array created by combining two arrays together to create a third array.
[ 1, 2, 3 ] + [ 4, 5 ] #=> [ 1, 2, 3, 4, 5 ] a = [ "a", "b", "c" ] c = a + [ "d", "e", "f" ] c #=> [ "a", "b", "c", "d", "e", "f" ] a #=> [ "a", "b", "c" ]
note that
x += y
coincides with
x = x + y
This means that it creates a new array. As a result, reusing the + = array on arrays can be quite inefficient.
Therefore, when you use += , it completely replaces the array, that is, the array in b[0] no longer matches b[1] or b[2] .
As you can see:
b = Array.new(3, []) b[0].push("test") b #=> [["test"], ["test"], ["test"]] b[0].object_id #=> 28424380 b[1].object_id #=> 28424380 b[2].object_id #=> 28424380 b[0] += ["foo"] b #=> [["test", "foo"], ["test"], ["test"]] b[0].object_id #=> 38275912 b[1].object_id #=> 28424380 b[2].object_id #=> 28424380
If you are wondering how to ensure that each array is unique when initializing an array of arrays, you can do this as follows:
b = Array.new(3) { [] }
This different syntax allows you to pass a block of code that runs for each cell to calculate its original value. Since a block is executed for each cell, a separate array is created each time.