1

I am trying to replicate an array of arrays and then modify the same element of each sub-array.

The following code is used to replicate the initial array of arrays:

const array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
const n = 2;  // replicate twice
let replicated_arrays = [];
for (let i = 0; i < n; i++) {    
    replicated_arrays.push(array);
}
replicated_arrays = [].concat.apply([], replicated_arrays);  // flatten to make one array of arrays 

The following code is then used to modify the second element of each array:

const init = 10;
replicated_arrays.forEach(function(element, index, entireArray) {
    entireArray[index][1] = init + index;
});

The desired output is:

[[1, 10, 3], [4, 11, 6], [7, 12, 9], [1, 13, 3], [4, 14, 6], [7, 15, 9]]

However, the above code produces the following:

[[1, 13, 3], [4, 14, 6], [7, 15, 9], [1, 13, 3], [4, 14, 6], [7, 15, 9]]

The forEach updates properly if the replicated array is created manually:

let replicated_arrays = [[1, 2, 3], [4, 5, 6], [7, 8, 9], [1, 2, 3], [4, 5, 6], [7, 8, 9]];

I therefore suspect it has something to do with the push method creating a reference to both instances of the initial array such that the final set of values (13, 14, and 15) are applied to both instances.

As an alternative to the push method, I tried the map method (e.g., in accordance with Duplicate an array an arbitrary number of times (javascript)), but it produced the same result.

Any insight or suggestions as to what is going on or how to make it work properly would be appreciated.

bryman79
  • 383
  • 1
  • 13

2 Answers2

2

You need to take copies of the inner arrays, because you need to lose the same object reference.

For pushing, you could spread the array and omit flattening later.

const array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
const n = 2;  // replicate twice
let replicated_arrays = [];
for (let i = 0; i < n; i++) {    
    replicated_arrays.push(...array.map(a => a.slice())); // spread array
}
// no need for this! replicated_arrays = [].concat.apply([], replicated_arrays);

const init = 10;
replicated_arrays.forEach(function(element, index) {
    element[1] = init + index; // access element directly without taking the outer array
});

console.log(replicated_arrays);
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
  • In looking through my full code, I see that I tried (unsuccessfully) to break the reference by pushing a copy. However, this works well. And nice use of the spread. Thank you very much. – bryman79 Jan 17 '19 at 09:09
0

Instead of concat use reduce method will keep same reference.

const array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
const n = 2;  // replicate twice
let replicated_arrays = [];
for (let i = 0; i < n; i++) {    
    replicated_arrays.push(array);
}
replicated_arrays = replicated_arrays.reduce(function(a, b){
   return a.concat(b);
}, []);

replicated_arrays.forEach((_ae,i) => {
   _ae[1] = 10 + i;
})
console.log(replicated_arrays);
output: [[1, 10, 3], [4, 11, 6], [7, 12, 9], [1, 13, 3], [4, 14, 6], [7, 15, 9]]
Omprakash Sharma
  • 409
  • 5
  • 11
  • Running in Chrome and Firefox and within a Node.js function, I get the same output I reported initially. How did you produce that output? – bryman79 Jan 17 '19 at 19:42