Skip to content

Home

Initialize a JavaScript array with a sequence of generated values

Have you ever needed to initialize an array with a sequence of generated values? Or perhaps you wanted to generate an array of values until a condition is met? While JavaScript's Array.prototype.map() may be your go-to solution, you might need to reach for some other tools to get the job done in some cases.

Initialize an array using a map function

At the most basic level, you can use the Array() constructor and Array.prototype.map() to initialize an array with a sequence of values. As the Array() constructor results in an array of empty slots, you may need to use Array.prototype.fill() to fill it with null values first to avoid any weird behavior.

const initializeMappedArray = (n, mapFn = (_, i) => i) =>
  Array(n).fill(null).map(mapFn);

initializeMappedArray(5); // [0, 1, 2, 3, 4]
initializeMappedArray(5, i => `item ${i + 1}`);
// ['item 1', 'item 2', 'item 3', 'item 4', 'item 5']

Initialize an array while a condition is met

The previous code snippet assumed that the length of the array to be created is known in advance. But what if you want to initialize an array while a condition is met? For example, you might want to generate the Fibonacci sequence until you reach a certain number. In this case, you can use a while loop to initialize the array.

const initializeArrayWhile = (conditionFn, mapFn) => {
  const arr = [];
  let i = 0;
  let el = mapFn(i, undefined, arr);
  while (conditionFn(i, el, arr)) {
    arr.push(el);
    i++;
    el = mapFn(i, el, arr);
  }
  return arr;
};

initializeArrayWhile(
  (i, val) => val < 10,
  (i, val, arr) => (i <= 1 ? 1 : val + arr[i - 2])
); // [1, 1, 2, 3, 5, 8]

In this code snippet, we create an empty array, arr, an index variable i and an element el. We then use a loop to add elements to the array, using the mapFn function, as long as the conditionFn function returns true.

The condition function, conditionFn, takes three arguments: the current index, the previous element and the array itself. The mapping function, mapFn, takes three arguments: the current index, the current element and the array itself.

šŸ’” Tip

You can easily alter the behavior of this function to add elements until the condition is met, using a do..while loop, instead.

Initialize an array using an iterator function & a seed value

Ramda's unfold() function provides another unique way to initialize an array. It accepts an initial seed value and an iterator function to generate the next value in the sequence. The iterator function must return an array with two elements: the next value in the sequence and the next seed value. If the iterator function returns false, the sequence is terminated. Here's a vanilla JavaScript implementation of this concept:

const unfold = (fn, seed) => {
  let result = [],
    val = [null, seed];
  while ((val = fn(val[1]))) result.push(val[0]);
  return result;
};

const f = n => (n > 50 ? false : [-n, n + 10]);
unfold(f, 10); // [-10, -20, -30, -40, -50]

Lazy initialization

As a side note, some of these operations can be time-consuming and memory-intensive. Oftentimes you may not need the entire array to be initialized at once. In these cases, you can use a generator function to lazily initialize the array.

As the array itself doesn't exist in memory, the mapping function can't access it. Instead, you can only pass the previous element as the second argument to the mapping function, allowing you to generate the next element in the sequence.

const generateArrayWhile = function* (conditionFn, mapFn) {
  let i = 0;
  let el = mapFn(i, undefined);
  while (conditionFn(i, el)) {
    yield el;
    i++;
    el = mapFn(i, el);
  }
};

const range5 = generateArrayWhile(i => i < 5, i => i);
[...range5]; // [0, 1, 2, 3, 4]

const doubleUntil50 = generateArrayWhile(
  (i, val) => val < 50,
  (i, val) => (i < 1 ? 1 : val * 2)
);
[...doubleUntil50]; // [1, 2, 4, 8, 16, 32]

This snippet implements a generator function that returns the next element in the sequence as long as the condition is met. The only major difference is that the mapping function only accepts two arguments: the current index and the previous element.

More like this

Start typing a keyphrase to see matching snippets.