Assigning a value to a JavaScript matrix inside of a forEach gone wrong

Viewed 31

The bitGraph.dfs() function returns an array of strings, with a format of 'i,j'. The matrix ends up with columns of ones and zeros. The goal is to have the indexes parsed from the strings of the matrix assigned to ones.

I checked the debugger and the line result[x][y] = 1 doesn't execute with each forEach iteration, but instead assigns a 1 to each element of the y column of the matrix at the end of the forEach.

const result = Array(N).fill(Array(M).fill(0));

Inside of a for loop:

bitGraph.dfs(`${N - 1},${j}`, visited)
    .forEach(node => {
        const [x, y] = node.split(',')
            .map(index => Number(index));
        result[x][y] = 1;
    });

Example:

returned array: ['5,0', '4,0', '1,5', '1,4', '1,3']
result: [
    [ 1, 0, 0, 1, 1, 1 ],
    [ 1, 0, 0, 1, 1, 1 ],
    [ 1, 0, 0, 1, 1, 1 ],
    [ 1, 0, 0, 1, 1, 1 ],
    [ 1, 0, 0, 1, 1, 1 ],
    [ 1, 0, 0, 1, 1, 1 ]
]
2 Answers

Your

const result = Array(N).fill(Array(M).fill(0));

creates an array filled with N copies of a single Array(M).fill(0) array.

Thus modifying any of those N copies seems to modify all of them:

> const result = Array(3).fill(Array(4).fill("hello"));
(3) [Array(4), Array(4), Array(4)]
  0: (4) ['hello', 'hello', 'hello', 'hello']
  1: (4) ['hello', 'hello', 'hello', 'hello']
  2: (4) ['hello', 'hello', 'hello', 'hello']
> result[0] === result[1]
true  # same object!
> result[0][2] = "zoop"
'zoop'
> result
(3) [Array(4), Array(4), Array(4)]
  0: (4) ['hello', 'hello', 'zoop', 'hello']
  1: (4) ['hello', 'hello', 'zoop', 'hello']
  2: (4) ['hello', 'hello', 'zoop', 'hello']

You'll need something like

const result = Array(N).fill(0).map(_ => Array(M).fill(0));

i.e. fill the array with N zeroes, then replace them with unique new M-length arrays. (You can't just use .map without the .fill, since the array is full of empty objects that aren't mapped over.)

Voilà:

> const result = Array(3).fill(0).map(_ => Array(4).fill("hello"));
> result[0] === result[1]
false
> result[0][2] = "zoop"
'zoop'
> result
(3) [Array(4), Array(4), Array(4)]
  0: (4) ['hello', 'hello', 'zoop', 'hello']
  1: (4) ['hello', 'hello', 'hello', 'hello']
  2: (4) ['hello', 'hello', 'hello', 'hello']

Try this :

// returned array from bitGraph.dfs()
let arr = ['5,0', '4,0', '1,5', '1,4', '1,3'];

// Decalring an empty array which will store the matrix result.
let result = [];

// Loop to create a multidimensional result array and fill with 0 as a default value.
for (let i = 0; i <= arr.length; i++) {
    const defaultArr = Array(arr.length + 1).fill(0);
  result.push(defaultArr);
}

// Iterating the input array by using Array.forEach() and do the matrix assignment
arr.forEach(node => {
  const [x, y] = node.split(',')
  .map(index => Number(index));
  result[x][y] = 1;
});

// Result
console.log(result);

Related