Patrick Assoa / Blog / Arrays / Power Javascript Array Initialization
gray GE volt meter at 414

Power Javascript Array Initialization

Introduction

Essentially, initializing arrays in javascript can happen in one of four ways:

  • With Array literal initialization, such as in let myArray = [1,2]
  • With Array initialization with undefined, as in new Array(arrayLength)
  • With Array initialization with given elements, as in new Array(el1,el2)
  • With the Array.prototype.of method, as in Array.of(7) // -> [7]

This being known, there eventually comes a time when a learning javascript developer will need to have more control over the initialization of arrays. In the coming sections we will explore common array initialization questions, as well as some solutions for the power javascript developer to-be.

Question: How to initialize an array with the same value?

It’s a recurring question. That is the developer wants to initialize an array, of a given length with the same value in each slots of the array. Obviously, what the developer is asking here is what is the most elegant way to do so. A straightforward way to do so is:

Question: How to initialize an array with sequential numbers?

Here we won’t use Array.prototype.fill. Instead, the developer will do something like:

Or better yet, the power developer might want to use generators:

[A] Generator is an object returned by a generator function and that conforms to both the iterable protocol and the iterator protocol. […] The iterable protocol allows JavaScript objects to define or customize their iteration behavior, such as what values are looped over in a for..of construct. […] The iterator protocol defines a standard way to produce a sequence of values (either finite or infinite), and potentially a return value when all values have been generated. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols

Such a developer might write:

Here a generator that yields numbers between from and to is used to construct an array. The fact that generators are iteratable is used with the spread ... operator to concisely initialize our sequential number array. It’s easy to see that we can now also have a fill function that can fill from an arbitrary number to another, as in:

Question: How to initialize an array with a recurring pattern of numbers?

An quick and dirty way to achieve this is:

This would work with arrays of characters too, as in if xs were something like "Hello".split(''). As you might have guessed, the power javascript developer will sense that there is room for improvement here. Inspired by the Haskell cycle and take function, he will probably write:

Here, the power developer might once again think of the ECMAScript 2015 iterator protocol:

The iterator protocol defines a standard way to produce a sequence of values (either finite or infinite), and potentially a return value when all values have been generated.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols

It stipulates that an ECMAScript iterator should have a next() method that returns a {value:any, done:boolean} object that contains the value returned by the iterator and done that is false if more values are held by the iterator or true otherwise. You will note, in the gist above, that the iterator returned by cycle never sets doneto true. Meaning, it is never out of values to yield. It just cycles through them. Please keep it in mind, as cycle is an important component of what we will do in the rest the article. Now, using repeatPattern2 will give the same result as repeatPattern. However, cycle and take allow us to do more interesting things, like answering the next question.

How to initialize an array by cycling through a sequence of elements?

That is, if given an array [1,2,3] and n=4, how to use it to initialize an array arr, such that arr is [1,2,3,1]? Using cycle and take, we can write the following function:

This will do the job for any pattern of elements.

Remember the first question? How to initialize an array with the same element? Now, if we change our cycle function like so:

It will accept single elements and we can have the function same:

It will return an array of the length specified n filled in with the specified element el. As in fiveOnes = same(1,5) // -> [1,1,1,1,1] or threeEmptyObjects = same({},3) // -> [{},{},{}]

With another small change, cycle can be used to provide a powerful and flexible way to initialize an array by cycling through a sequence of numbers:

Now, cycle can accept:

  • a single element to cycle through
  • an array of elements to cycle through, or
  • two numbers x,y in order to generate a sequence of number in the range x..y, from which it will cycle.

The method cycleThroughNumberPattern(x,y,n) essentially uses the cycle(x,y) form of cycle to become a more powerful version of our earlier arrayFillSequential function.

Improvements on Cycle and Take

The take(n,xs) function can be made to directly accept arrays and be more robust. First we need to ensure that its xs parameter is not already an iterator object with typeof xs.next === 'undefined'. If not, we need a method to turn our array into an iterator. Also, we want to stop requesting elements from xs if xs contains less elements than n. Adding these changes, we finally have:

Earlier, we mentioned the iterable protocol. We might want to let our cycle function return an object that is also an iterable. This will allow us to retrieve the sequence our cycle is operating on by using the spread ... operator. So our modified cycle function is now:

Bonus Question: How to initialize an array by cycling through a sequence of random numbers?

First the power developer, that you are, needs a way to generate random numbers sequences of arbitrary length. Here is how he does it:

The important part here is our randomFiller generator that only yields once, but when it does, what is yielded is assured to be an array of length n containing n unique random numbers between min and max.

Then, all that is left to do is to use take and cycle to generate an array cycling through the generated random numbers; for example:

take(15, cycle(randomNumberSequence(1,30,10)))

Conclusion

The cycle and take functions, with the support of generators, will help the power javascript developer craft array generation functions that are elegant and powerful. To take what we just spoke about further, the lucid javascript developer will want to use partial application, compose and currying to build even more powerful array generation tools.

The code for this article can be found at https://github.com/kanian/power-js-array-initialization-article