0

Today I was porting my Python code into JavaScript and found this behavior.

Code:

var a = new Array(2).fill(new Array(3).fill([0, 0]));
for (i=0; i<2; i++) {
  for (j=0; j<3; j++) {
    a[i][j] = [i, j];
    //console.table(a); //for debugging
  }
}

What I think I should get for a (as a 2-dim array):

--------------------------
[0, 0] | [0, 1] | [0, 2] |
--------------------------
[1, 0] | [1, 1] | [1, 2] |
--------------------------

What JavaScript gave me:

--------------------------
[1, 0] | [1, 1] | [1, 2] |
--------------------------
[1, 0] | [1, 1] | [1, 2] |
--------------------------

It looks like there's some other type of logic used in JavaScript than what I think it should be. I'm simply assigning [i, j] to the [i][j]-th entry, but the result is not what I have in mind.

  1. Have I made a mistake in the code?
  2. Why is the for-loop logic doesn't work in JavaScript?
  3. What should I do to get the desired result then?
Som Shekhar Mukherjee
  • 4,701
  • 1
  • 12
  • 28
  • how do you print out the array contents? – mangusta Nov 01 '20 at 04:09
  • 1
    Because you're using `Array.fill`, `a[1]` is a reference to `a[0]`, so when you change `a[1][0]` you also change `a[0][0]`. – Nick Nov 01 '20 at 04:10
  • See [this question](https://stackoverflow.com/questions/966225/how-can-i-create-a-two-dimensional-array-in-javascript) for how to properly create an empty 2-d array. – Nick Nov 01 '20 at 04:11
  • 1
    The key is that `.fill()` does not fill the outer array with *copies* of the inner array, but with references to the same *single* array. – Pointy Nov 01 '20 at 04:12

2 Answers2

1

If we run:

let a = new Array(2).fill(new Array(3).fill([0, 0]));
for (let i=0; i<2; i++) {
  for (let j=0; j<3; j++) {
    a[i][j] = [i, j];
    console.log(a[i][j]);
  }
}
console.log(a);

We find that there's nothing wrong with the loop's logic itself. It is going in the correct order for i and j. So what's the problem? It turns out that JavaScript's Array.fill() method creates copies by references, not values! In other words, each element is basically a reference pointing to the same array, not individual separate arrays. To fix this for your code, use Array.from():

let a = Array.from({length: 2}, e => Array.from({length:3}, e => [0, 0]));
for (let i=0; i<2; i++) {
  for (let j=0; j<3; j++) {
    a[i][j] = [i, j];
    console.log(a[i][j]);
  }
}
console.log(a);
General Poxter
  • 554
  • 2
  • 8
0

You can also simply do this without creating an array with zeroes (unless you need that array with zeroes). Use the push method on arrays.

let arr = [];
let nrows = 2;
let ncols = 3;

for (let i=0; i<nrows; i++) {
  for (let j=0; j<ncols; j++) {
    arr.push([i,j]);
  }
}

console.log(arr);
Som Shekhar Mukherjee
  • 4,701
  • 1
  • 12
  • 28