There maybe a situation where you want to pre-populate a default value for an array before further modifications along the execution course.
For a flat, single dimensional arrays, this works just like intended
arr.fill(-1);
What if you want to fill arr
with arrays? like a matrix or so, something like this, for a 2 x 3 matrix
let arr = [
[-1, -1, -1],
[-1, -1, -1]
];
One might say, well, I'm just gonna use fill
and pass an array as a parameter
let arr = Array(2);
arr.fill([-1, -1, -1]);
console.log(arr); //Prints same array like above
Piece of cake, right? not quite, not like the cake you'd like a piece of.
The problem
Lets look at a misbehavior for that approach that might cause you headaches, and see why that happens
//This is the array after usng fill
// [ [ -1, -1, -1 ], [ -1, -1, -1 ] ]
//Now set an element in one of the sub-arrays
arr[0][1] = 5;
console.log(arr);
// [ [ -1, 5, -1 ], [ -1, 5, -1 ] ]
//Oops! what just happend?
You see that? you've just set one element in one array, yet all elements in that position of all sub-arrays were set to the same value (i.e. if you had a third sub-array -or more, its element at position 1
will be set to 5 as well).
Why fill
won't work
if you look at the implementation docs for the Array.prototype.fill
method, you can see the reason for this behavior.
The simplified process of arr.fill(arg)
is like that..
for every position in arr:
arr[position] = arg
So the same arg
is assigned to each position, and arrays in Javascript are objects, so what's really passed is a reference to the same object in memory, that's why any change to one element affects the rest, they are the same thing.
This might be better demonstrated like below..
let b = [-1, -1, -1];
arr.fill(b);
the first line creates an array in memory and makes b
reference it, then b
is passed to the fill
method that assigns it to every position in the array, imagine arr now is something like: [ [b], [b], [b] ]
.
The fix
One possible one-liner fix would be to use ES 2015's Array.from
let arr = Array.from(Array(2), ()=>[-1, -1, -1]);
The first parameter is an iterable (In our case it's an empty array of length 2). The second parameter is a map function that's executed for each element, so every element is gonna be its own unique array.
Another way to handle this is a little trick with apply
on the Array
function (Array
can be used as a constructor or a function, so apply
is available to it)
let arr = Array.apply(null, Array(2)).
map(()=>[-1, -1, -1]);
The reason this works is that Array()
creates a bunch of holes (empty spots), and map
ignores these holes, so we use apply
because it fills these holes with undefined
so map
can see these.
These are meant to be quick one-liners to solve the problem. You can always fall back to iterating through the array and assigning the value to each position
That's it, feel free to share thoughts, ask questions and fill in gaps.
No comments:
Post a Comment