Reputation: 429
This is probably a duplicate question but I didn't know how to search for it.
Can someone explain the bevior from the code snippet to me?
I am trying to iterate over a 2-dimensional array, setting each value to the index of the containing row. Yet all values are somehow set to the last row's index.
const string1 = "abc";
const string2 = "abcd";
const matrix = new Array(string1.length).fill(new Array(string2.length).fill(0));
for (let i = 0; i < string1.length; i++) {
for (let j = 0; j < string2.length; j++) {
console.log(i);
matrix[i][j] = i;
}
}
console.log(matrix);
Output:
0
0
0
0
1
1
1
1
2
2
2
2
[ [ 2, 2, 2, 2 ], [ 2, 2, 2, 2 ], [ 2, 2, 2, 2 ] ]
Expected output:
0
0
0
0
1
1
1
1
2
2
2
2
[ [ 0, 0, 0, 0 ], [ 1, 1, 1, 1 ], [ 2, 2, 2, 2 ] ]
Upvotes: 2
Views: 66
Reputation: 19354
The issue is that in the posted code, the call to
.fill(new Array(string2.length)
creates a single array when evaluating fill
's argument, which in turn means fill
will set all elements of the array it is called on to the selfsame Array object.
This way this snippet creates second dimensional arrays only involves creating a single array for matrix
's first dimensional array:
const string1 = "abc";
const string2 = "abcd";
const matrix = new Array(string1.length).fill(0);
matrix.forEach( (_, i, rows) => rows[i] = new Array(string2.length).fill(i));
console.log( matrix)
console.log("\nSee note about spread for this: ", [...new Array(string1.length)]);
Notes
Array prototype methods such as forEach
and map
do not process empty slots in arrays they are called on (i.e. they skip over array entries that have not been assigned a value).
The fill(0)
call at the end of the matrix
declaration in the snippet ensures none of its slots are empty. (It could have used fill()
with no argument to fill empty slots with undefined
).
Of interest, but not used in the snippet, using spread syntax to initialize one array from another converts empty slots in the spread array to elements with the value undefined
in the initialized array
Upvotes: 1
Reputation: 348
Maybe the following workaround will helpful to get the final result.
const string1 = "abc";
const string2 = "abcd";
const matrix = [];
for (let i = 0; i < string1.length; i++) {
const arrayJ = [];
for (let j = 0; j < string2.length; j++) {
arrayJ.push(i);
}
matrix.push(arrayJ);
}
console.log(matrix);
Upvotes: 0
Reputation: 9228
See the documentation:
fill()
changes all values of an array to a staticvalue
. [...] Note all elements in the array will be this exact value: ifvalue
is an object, each slot in the array will reference that object.
That means in each of your rows you will reference the same object (= Array, remember: arrays are objects in JavaScript) meaning you always change the same array resulting in the last change being the one you can observe by printing it.
const string1 = "abc";
const string2 = "abcd";
const matrix = new Array(string1.length).fill(new Array(string2.length).fill(0));
for (let i = 0; i < string1.length; i++) {
for (let j = 0; j < string2.length; j++) {
matrix[i][j] = i;
}
}
console.log(JSON.stringify(matrix));
// Prove that they are actually the same reference => same object
console.log(matrix[0] === matrix[1]) // true
You could use the following approach to initialize the array.
const string1 = "abc";
const string2 = "abcd";
const matrix = [...new Array(string1.length)].map((_, i) => new Array(string2.length).fill(i));
console.log(JSON.stringify(matrix));
// now we have different references => different objects
console.log(matrix[0] === matrix[1]) // returns false
Upvotes: 1