Array Ruby + = vs push

I have an array of arrays and you want to add elements to sub-arrays. + = does what I want, but I would like to understand why push does not.

The behavior I expect (and works with + =):

b = Array.new(3,[]) b[0] += ["apple"] b[1] += ["orange"] b[2] += ["frog"] 

b => [["apple"], ["orange"], ["frog"]]

With a click, I get a pushable item added to EVERY submatrix (why?):

 a = Array.new(3,[]) a[0].push("apple") a[1].push("orange") a[2].push("frog") 

a => [["apple", "orange", "frog"], ["apple", "orange", "frog"], ["apple", "orange", "frog"]]

Any help on this is greatly appreciated.

+5
source share
2 answers

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 #=> 28424380 b[1].object_id #=> 28424380 b[2].object_id #=> 28424380 

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.

+9
source

This is because in the second section of the code you select a sub-array and click on it, if you need an array of the array, you need to push the array to the main array.

 a = Array.new(3,[]) a.push(["apple"]) a.push(["orange"]) a.push(["frog"]) 

to get the same result as the first.

EDIT: I forgot to mention, because you initialize an array with an empty array as elements, you will have three empty elements before the pressed elements,

0
source

Source: https://habr.com/ru/post/1270683/


All Articles