Modifying one index of multidementional array causes every other child array to mutate?

Viewed 56

So, I've initialized a multidimensional array like this.

let arr = new Array(5).fill(new Array(5).fill(0));

doing

arr[2][3] = 1;

Will give us

0 0 0 0 0
0 0 0 0 0
1 1 1 1 1
0 0 0 0 0
0 0 0 0 0

Why is this? I would guess it's a pass by reference issue and that's just a single array with references in each subsequent index, but I'm creating a new one, so why does this happen?

let arr = new Array(5).fill(new Array(5).fill(0));
arr[2][3] = 1;
console.log(JSON.stringify(arr));

3 Answers

new Array(5).fill(0) just creates one array that's filled with zeroes. You then fill the outer array with 5 references to that same array.

You can see what's happening more easily if you write the equivalent code:

let row = new Array(5).fill(0);
arr = new Array(5).fill(row);

There's just one row array, and you fill arr with references to it.

You need to use a loop so you create a new array for each row.

arr = [];
for (let i = 0; i < 5; i++) {
    arr.push(new Array(5).fill(0))
}

You are filling the top level array with same instance of nested array. The function fill() only fills the array with the same instance 5 times.

You could change to the following. By calling map() you ensure the nested array creation calls 5 times.

let arr = new Array(5).fill(0).map(_ => new Array(5).fill(0));
arr[2][3] = 1;
console.log(JSON.stringify(arr));

In my mind the correct way is:

let arr = Array.from(Array(5),x=>Array.from(Array(5),y=>0))

arr[2][3] = 1;

arr.forEach((row,idx)=> console.log('idx>',idx, JSON.stringify(row)) )
.as-console-wrapper { max-height: 100% !important; top: 0; }

Related