Unexpected Behavior Using Array Map on an Array Initialized with Array Fill

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 filling 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



Leave a reply



Submit