reduce() in JavaScript

Hero image for Reduce() in JavaScript. Image by John Cameron.
Hero image for 'Reduce() in JavaScript.' Image by John Cameron.

It feels like a very long time since I wrote about JavaScript's filter() method, so in the interest of completeness, I'm looping back to cover two other array manipulation methods: reduce(), and map(). Today, it's the turn of reduce(), which is probably one of the more daunting array manipulation tools, but we'll get to that shortly...


Understanding reduce()

Unlike filter() and map(), the reduce() method is a little more difficult to get a handle on. It is basically a method for processing data stored within arrays, by systematically working through the array, and apply a function to accumulate its elements into a single output value. I'll (hopefully!) do a better job of describing it when we come to the examples/etc below, but for now, think of it a little like a collector: it takes in scattered sets of elements and combines them together into something more manageable and unified.

Fundamentals

reduce() belongs to the Array prototype (Array.prototype.reduce()), and so is universally accessible across array instances in JavaScript.

At a minimum, it requires one argument: a reducer function which is called on each element of the array. This reducer function receives four parameters:

  1. Accumulator

    : The accumulated returned from the last invocation of the callback, or its initial value.
  2. Current Value

    : The element currently being processed.
  3. Index

    (optional): The index of the current element.
  4. Array

    (optional): The array reduce() was called upon.

In addition to these, reduce() can also accept an optional second argument, used to set the initial value of the accumulator.

Syntax

I've already talked about the parameters and arguments that reduce() can accept above, so here's the formal syntax:

const result = array.reduce(function(accumulator, currentValue, index, arr), initialValue);

A Simple Example

The classic example when trying to explain reduce() is to use it to add together all the numbers within an array:

const numbers = [1, 2, 3, 4, 5];const sum = numbers.reduce((acc, current) => acc + current, 0);console.log(sum);//=> 15

Here, you can see that reduce() traverses the numbers array, adding each number to a cumulative total (acc), which has been set to start at 0.


A More Complex Example

For a more indepth example, imagine you have a set of data representing votes for your team's most handsome developer, and you want to tally the votes for each candidate.

const votes = ['John', 'Andy', 'John', 'John', 'Andy', 'Mark'];const voteCounts = votes.reduce((acc, vote) => {  acc[vote] = (acc[vote] || 0) + 1;  return acc;}, {});console.log(voteCounts);//=> { John: 3, Andy: 2, Mark: 1 }

Here, we're using reduce() as a tallying mechanism, transforming an array of individual votes into an object where each property represents a candidate and their total votes. The results are hardly surprising!

As a brief aside here: if you're using TypeScript then the code above will throw a couple of warnings around typing because using the empty object {} as the initial value indicates an object with no properties. If you wanted to define the type of the accumulator object explicitly, the code would look more like this:

const votes = ['John', 'Andy', 'John', 'John', 'Andy', 'Mark'];const voteCounts = votes.reduce((acc: { [key: string]: number }, vote) => {  acc[vote] = (acc[vote] || 0) + 1;  return acc;}, {} as { [key: string]: number });console.log(voteCounts);//=> { John: 3, Andy: 2, Mark: 1 }

... I still won though...!


Tips for using reduce()

Versatility

reduce() can be used for more than just calculations on numerics. It can be used to outright transform arrays, or compile data into new structures. The difference to map() is that you have access to the accumulator, so you can create a tighter relationship between array elements.

Initial Value

Whilst it is optional, I would always suggest providing an initial value for the accumulator. That way, you ensure that your reducer behaves predictively, especially with empty or heterogeneous data sources.

Complexity Management

Whilst very powerful, reduce() can very quickly make your code harder to read, especially for complex operations. At the very least, I would expect to see a cheeky comment above anything more complicated than a threeline reduce(), simply to offer guidance to whoever comes next.


Wrapping up

If you need to collect and transform data, where the expected output needs to rely on the value of previous items within the array, when the reduce() method is almost certainly the right choice.


Categories:

  1. Development
  2. Guides
  3. JavaScript