DEV Community

Cover image for Performing repetitive calls using an ad-hoc array
Tracy Gilmore
Tracy Gilmore

Posted on • Updated on

Performing repetitive calls using an ad-hoc array

One of the most common uses for the common JS for loop must be to traverse the elements of an array. It might be to transform each element, filter a sub-set or convert the entire array into an entirely new data structure. This is probably the reason why the Array prototype acquired some super powers in ECMAScript 6 (ES 2015) in the form of some additional methods (map, filter, reduce, etc.) These methods make the code simpler to write (largely), understand and, being implemented inside the JS engine, has the potential to offer better performance.

Most of the new methods follow a common pattern in that they take a call-back function that is applied to each item in the array in turn. The majority of the methods return a brand new array (or another object) as the output. The call-back functions are typically one of three types:

  • Transform: Converts the input item in to a new item
  • Predicate: Applies some logic on the input item and returns a Boolean value as the result
  • Reducer: Takes in two parameters, the second being the array item, the first being a 'running total' and produces an updated 'running total'.

Two additional points:

  1. I used the term 'running total' to describe the first parameter of the reducer but that is not to say it has to be a numeric value. It could be another array, an object or any value that gets passed from one cycle to the next.
  2. The call-backs actually take in more that 1 argument (or 2 arguments in the case of reduce). In addition to each item from the array it also takes the index of the item and the array itself.

But how can you test the call-backs without creating an array of test data. Here is where the adhocArray function comes in useful, although I can also imagine scenarios where the function could be used in operational code.

Using an ad-hoc Array

As explained above, the majority of the time the call-backs need to operate on the items of an array. We can exercise the call-backs directly but ideally we still need a range of input values/objects.

The primary use case for the ad-hoc array is to exercise Pure functions, which are highly reusable, usually easy to test but often require additional inputs to make up for a lack of context. Pure functions operate entirely on their parameters and nothing outside of that including not changing the value of arguments supplied by reference. They only output via the return value which is deterministic and predictable from the input.

Implementation

I have experimented with a number of varieties of functions but the following is my preferred implementation to date. It works by first defining an Array of the required size but this only allocates space. The initial Array is expanding it out into another Array, which creates a populated Array. Finally the transform call-back function (default or supplied) is used to convert the index of each element of the array into a new array.

function adhocArray(length = 1, transform = _ => _) {
  return [...Array(length).keys()].map(transform);
}
Enter fullscreen mode Exit fullscreen mode

An arrow function could easily be used in place of a conventional function but this limits where the function can be declared. Through JS hoisting conventional functions can be declared at the bottom of a script and used before the declaration. This not true of arrow functions that have to be declared before they can be used.

Usage

The adhocArray function enables us to execute a function a set number of times. We have the option of using the content of the array that has been especially created for the purpose. Now lets investigate its behaviour through a few experiments.

Default execution

console.log(adhocArray(6));  // [ 0, 1, 2, 3, 4, 5 ]
Enter fullscreen mode Exit fullscreen mode

At first sight this might appear to be no different to creating an Array by just calling Array(6) but that would create an array of 6 empty elements. Using adhocArray we get back an array repopulated, by default with integers incrementing from zero.

Basic transform

const evenValues =  i => (i + 1) * 2;
console.log(adhocArray(6, evenValues));  // [ 2, 4, 6, 8, 10, 12 ]
Enter fullscreen mode Exit fullscreen mode

We can customise the array population using a supplied transform call-back that converts the default integer into whatever is required.

Basic transform with post processing (reduce-based sum)

const evenValues =  i => (i + 1) * 2;
const sum = (total, inc) => total + inc;
console.log(adhocArray(6, evenValues).reduce(sum));  // 42
Enter fullscreen mode Exit fullscreen mode

The array output can the be used for a variety of purposes but its original use case was to enable execution of a (call-back) function a set number of times; to render dummy data in a prototype screen for instance. In the above example I have used it to exercise an experimental reduce-based sum reducer.

Populating a 2-dimensional array

const multiplier = (_, __) => (_ + 1) * (__ + 1);
const timesTable = adhocArray(12, _ =>
  adhocArray(12, __ => multiplier(_, __))
);
console.table(timesTable);
Enter fullscreen mode Exit fullscreen mode

Combining adhocArray can also produce a 2-dimensional data set. In this example I have used it to generate a 12x12 times table.

Times table otput

Bonus transforms

When creating a form that requires a day-of-week or month-of-year input it is not unusual to encounter a variable such as;

const DAYS_OF_WEEK = [
  'Sunday',
  'Monday',
  'Tuesday',
  'Wednesday',
  'Thursday',
  'Friday',
  'Saturday'
];
Enter fullscreen mode Exit fullscreen mode

But what if you need the list to be in another or multiple languages. We can use the JavaScript Intl namespace using the following utility functions to generate day and month names in long or short forms, in a variety of languages (defaulted to British English).

const shortDay = (day, lang = 'en-GB') =>
  new Date(0, 0, day).toLocaleString(lang, { weekday: 'short' });

const longDay = (day, lang = 'en-GB') =>
  new Date(0, 0, day).toLocaleString(lang, { weekday: 'long' });

const shortMonth = (mon, lang = 'en-GB') =>
  new Date(0, mon, 1).toLocaleString(lang, { month: 'short' });

const longMonth = (mon, lang = 'en-GB') =>
  new Date(0, mon, 1).toLocaleString(lang, { month: 'long' });
Enter fullscreen mode Exit fullscreen mode

Here is a demonstration:

console.log(adhocArray(7, shortDay));
console.log(adhocArray(12, shortMonth));

/* Output - Default short day and month in GB English
[
  'Sun', 'Mon',
  'Tue', 'Wed',
  'Thu', 'Fri',
  'Sat'
]
[
  'Jan', 'Feb', 'Mar',
  'Apr', 'May', 'Jun',
  'Jul', 'Aug', 'Sept',
  'Oct', 'Nov', 'Dec'
]
*/

console.log(adhocArray(7, day => longDay(day, 'ga-IE')));

/* Output - Gaelic days of the week (in long form)
[
  'Dé Domhnaigh',
  'Dé Luain',
  'Dé Máirt',
  'Dé Céadaoin',
  'Déardaoin',
  'Dé hAoine',
  'Dé Sathairn'
]
*/

console.log(adhocArray(12, mon => longMonth(mon, 'fr-FR')));

/* Output - French months in long form
[
  'janvier',   'février',
  'mars',      'avril',
  'mai',       'juin',
  'juillet',   'août',
  'septembre', 'octobre',
  'novembre',  'décembre'
]
*/
Enter fullscreen mode Exit fullscreen mode

To Close

I am not convinced the adhocArray has any real utility but I found it a useful and interesting exercise all the same. And besides it saves me another reason for writing boring for loops.

Latest comments (0)