Unexpected behavior using Array Map on an Array Initialized with Array Fill
Your code is equivalent to:
let inner = Array(3).fill(0);
let M = Array(3).fill(inner);
When you pass inner
to .fill()
, it doesn't make copies of it, the M
array contains 3 references to the same array. So anything you do to one element of M
happens to them all.
You need to make new arrays for each element of M
:
let M = [];
for (var i = 0; i < 3; i++) {
M.push(Array(3).fill(0));
}
Array.prototype.fill() different from fill as I go
Array.fill
is intended to be used to fill all the elements of an array from a start index to an end index with a static value.
This unfortunately means that if you pass in an element such as a new array, your array will actually be filled with many references to that same element. In other words, a
is not filled with six arrays of size six; a
is filled with six pointers to the same array of size six.
You can easily verify this in your developer console:
var a = new Array(6).fill(new Array(6).fill(0));
a
>>> [Array[6], Array[6], Array[6], Array[6], Array[6], Array[6]]
a[0]
>>> [0, 0, 0, 0, 0, 0]
a[1]
>>> [0, 0, 0, 0, 0, 0]
a[0][1] = 1
a[0]
>>> [0, 1, 0, 0, 0, 0]
a[1]
>>> [0, 1, 0, 0, 0, 0]
Weird Leetcode Bug: Array.fill() vs new Array.from()
In the first case you are filling the array with the same Array
instance. In the second case every row is a new Array
because you provided a factory function.
const m = 3;
let memo = new Array(m).fill(new Array(m).fill(-Infinity));
console.log(memo[0] === memo[1]); // true
Strange behavior when modifying an array of Objects
You're fill
ing the array with the same object. (We can see this by using the ===
strict equality operator.)
> balances = Array(5).fill({})
(5) [{…}, {…}, {…}, {…}, {…}]
> balances[0] === balances[1]
true
You'll need to construct an object for each slot - an FP (if not necessarily pretty or efficient) way to do this would be
> balances = Array(5).fill(null).map(() => ({}))
(5) [{…}, {…}, {…}, {…}, {…}]
> balances[0] === balances[1]
false
A non-FP, old-school, imperative but plenty fast (79% faster than the one above, by one quick benchmark) way is simply
var balances = [];
for(let i = 0; i < 5; i++) balances.push({});
Why do multiple calls of Array.fill effect unreferenced arrays?
Your code is equivalent to
let row = [0,0,0]
let matrix = [row, row, row];
row.fill(1);
because .fill(Array(3).fill(0))
calls Array(3).fill(0)
once to get the fill value - if the fill argument were a callback, then it would call it for each item in matrix - but the fill argument is a value
In javascript, arrays are said to be a reference
var a = [1,2,3], b=a;
b[0] = 4
will result in both a
and b
referencing an array with values [4,2,3]
so, since each row
is the same array, your result is as you've seen
try this instead
const matrix = Array.from({length:3}, () => Array(3).fill(0))matrix[0].fill(1);console.log(matrix);
Setting the value in a matrix after fill() returns incorrect matrix
When you do this:
x = [["O", "O", "O"], ["O", "O", "O"], ["O", "O", "O"]];
Javascript is creating 3 different Arrays in memory, so when you access x[0][1]
you're accessing just that array.
When you are using the:
x = new Array(3).fill(new Array(3).fill('O'))
You are basically filling the array with same array 3 times, so when you access x[0][1]
you're accessing the same Array in memory that's also connected to x[1]
and x[2]
.
As commented by @Shidersz, a possible iterative solution would be:
// one liner:
Array.from({length: 3}, x => new Array(3).fill("0"));
This is creates an array and populates it with the values returned from the inputed function. Here's a breakdown:
// same as previous only longer with comments
// Create an Array from the first argument,
//as modified by the mapping function in the 2nd argument
Array.from(
// This could be any array like object.
// In the case of length it just reads the length property
// and iterates that number of times,
// so it could be useful if you want to
// fill the top array with 100000 arrays.
{length: 3},
// x argument for the mapping is irrelevant
x => {
// returning the array with 3 "0" strings in it.
return new Array(3).fill("0")
});
docs here for more reference.
Array.prototype.fill intended behavior on reference types
It is the intended behavior according to the spec. The value is not cloned.
Array.fill uses the same object for all indices
Yes it does.
You are passing a reference to an created object instance.
If you would first declare the array (eg. var c = []
) and then populate arr
with it you would get the same behavior.
const c = [];
const arr = Array(2).fill(c);
c.push("a");
c.push("b");
// c ["a", "b"]
// arr [reference to c, reference to c] => [["a","b"], ["a", "b"]]
javascript use Array fill() function to init a 2D array
That happens because dp.fill()
is using a reference to the same array, defined by new Array(n).fill(false)
. When you change dp[0]
, you also "change" dp[1]
, dp[2]
, etc...
So you should use the code you posted below.
Related Topics
How to Guarantee That My Enums Definition Doesn't Change in JavaScript
How to Use Redirect in Version 5 of React-Router-Dom of Reactjs
How to Execute Shell Command in JavaScript
Set Additional Data to Highcharts Series
How Does Variable Assignment Work in JavaScript
Getting Scroll Bar Width Using JavaScript
When Does Js Interpret {} as an Empty Block Instead of an Empty Object
JavaScript Get Window X/Y Position for Scroll
Convert Hh:Mm:Ss String to Seconds Only in JavaScript
JavaScript - Get the First Day of the Week from Current Date
Invalid Hook Call. Hooks Can Only Be Called Inside of the Body of a Function Component
Equivalent of String.Format in Jquery
Check If Event Exists on Element
Get Protocol, Domain, and Port from Url