3

I am working on a problem that outputs its results into a 2D array, adding one to each element as it goes.

I simplified the code down as far as I could to create a test case. If I fill the array as a I go, as follows:

var a = [[], [], [] ,[] ,[], []];
var d1, d2;
for (d1 = 0; d1 < 6; d1++) {
    for (d2 = 0; d2 < 6; d2++) {
        a[d1][d2] = (a[d1][d2]) ? (a[d1][d2]) + 1 : 1; 
    }
}

I get a 2D array where all the values are 1. However, if I prefill the array using array.prototype.fill() as follows:

var a = new Array(6).fill(new Array(6).fill(0));
var d1, d2;
for (d1 = 0; d1 < 6; d1++) {
    for (d2 = 0; d2 < 6; d2++) {
        a[d1][d2] += 1; 
    }
}

I get a 2D array full of 6s. Even if I replace a[d1][d2] += 1 with the old a[d1][d2] = (a[d1][d2]) ? (a[d1][d2]) + 1 : 1;, (which should still work since both 0 and undefined are falsy) I still get 6s.

As far as I can tell, my code should just loop through each element and add one to the previous value. It shouldn't touch any element more than once, so they should all be 1s. Whether I fill the array ahead of time or not shouldn't matter.

Where is the failure in my understanding?

trlkly
  • 681
  • 7
  • 13
  • Pop quiz: how many new array objects does the line `new Array(6).fill(new Array(6).fill(0));` create? (Hint: it's the same number as the number of `new Array` calls that appear in the line.) (Hint #2: It's less than 7 `:)`.) – apsillers Apr 19 '16 at 00:57

1 Answers1

6

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]
Hamms
  • 5,016
  • 21
  • 28
  • 1
    In other words (for the OP's benefit), each version of `a[d1]` is always the *exact same array*, so each of its six values gets augmented six times. – apsillers Apr 19 '16 at 01:01
  • @apsillers Igeddit, Igeddit. :) I haven't put in the green check yet cause I like to wait a bit, in case someone else comes along and explains it even more simply or more elegantly or includes something that would work as I intend.... – trlkly Apr 19 '16 at 01:23
  • 1
    You just need to use something other than `fill` for your outer array. I suggest `map` or `Array.from` – Hamms Apr 19 '16 at 02:20
  • I just wound up doing it with a for loop, and then going on to write a recursive function that could do it for any number of dimensions, with any number of elements per dimension, and an optional fill. And then I just stuck with my old method of filling as I go. – trlkly Apr 19 '16 at 06:42