The Reason
In a recent algorithm challenge, I wanted to create an iterable collection of ten "buckets" for grouping data. In practice, this meant creating an array of arrays like:
[[], [], [], [], [], [], [], [], [], []]
What Did Not Work
Rather than hard code each set of arrays, I wanted to create this dynamically. My first attempt (from memory and a cursory skim of the MDN docs), was to use the Array constructor with the .fill
method chained on:
const arr = new Array(10).fill([]);
console.log(arr);
// => [[], [], [], [], [], [], [], [], [], []];
At first glance, this seemed to work. Console logging my new arr
revealed an array containing 10 empty arrays, so I continued solving the algorithm.
As soon as I began populating the inner arrays (the buckets), I noticed that there was an issue - adding an element to one "bucket", for example at index 5, updated EVERY bucket to match, rather than only the intended bucket:
arr[5].push("hello");
console.log(arr);
// => [["hello"], ["hello"], ["hello"], ["hello"], ["hello"], ["hello"], ["hello"], ["hello"], ["hello"], ["hello"]];
Returning to the MDN docs for Array.prototype.fill
, the issue became clear:
As arrays are a type of object, each of my array buckets were actually referencing the same object in memory. So rather than creating 10 distinct arrays, my array was merely displaying 10 copies of the same array.
Array.from
to the Rescue
To dynamically create an array of arrays (or other objects), you can instead use the .from
method:
const newArr = Array.from({ length: 10 }, () => []);
console.log(newArr);
// => [[], [], [], [], [], [], [], [], [], []];
Per MDN, Array.from
accepts an iterable or "array-like" object as it's first argument, and an optional callback function ("mapFn") for a second argument.
Here, {length: 10}
is an "array-like" object which will provide the length of the array being created.
The second argument () => []
is the "mapFn", which is called for each element and whose return value is used to populate the array.
Now, pushing an element to the array at index 5, updates only that array, as expected:
newArr[5].push("hello");
console.log(newArr);
// => [[], [], [], [], [], ["hello"], [], [], [], []];
Top comments (1)
Interesting 🤯 Thanks for the explanation and concise solution!