loading...

Demystifying Array.reduce(): How to understand it and when to use it in your code

nickyhajal profile image Nicky Hajal 惻3 min read

ES5 and later versions of JavaScript brought several new methods for handling arrays. Many of them have become the best practice for common tasks with arrays and JavaScript is much better off with them.

Array.map() and Array.filter() are two examples of daily-driver ES5 additions that are staples for most JS developers.

An equally useful but often less understood tool in the kit is Array.reduce(). Lately, I've been using reduce more often, but it took a while for it to feel natural and I often see other developers struggling with it... or just not using it at all.

Reduce is often taught wrong and therefore misunderstood

In my opinion, a large reason for the confusion is that reduce is just taught wrong. In fact, it even feels named wrong to me (even though, of course, the concept and name of a reducer come from well before it was added to JavaScript).

The most common example when teaching reducers is something like this:

const array = [1, 2, 3, 4];
const sum = array.reduce((accumulator, currentItem) => {
    return accumulator + currentItem;
}, 0);

// sum = 10

This fairly cleanly shows how reducers function. You call reduce() on an array and pass it an initial value as well as a function that runs for each item of that array.

To the passed function, reduce sends:

1) The current item and
2) The value returned by the previous callback (or the initial state, when called for the first time)

The final value of reduce is ultimately whatever the inner reducer function returns when called the last time.

As a result, in this case, the reducer is summing the values of the array and returning the total value.

So... adding arrays of numbers, is that all Reduce does?

I saw that example so many times, but rarely saw explanations that went much further.

"Hm, interesting.", I'd think, as I went on with my day.

So, what's the real deal with reducers? What are they actually good for?

Here's the real power:

Reducers are useful when you want to process an array but output something that isn't an array

That's really what it boils down to, and that is useful very often.

After all, isn't that what we're doing in the example above? We're taking in an array and returning an integer. In that context, it makes some sense that we're "reducing" the array, but we don't always have to output something as simple as an integer.

Take this example:

const trips = [{type: 'car', dist: 42}, {type: 'foot', dist: 3}, {type:'flight', dist: 212}, {type: 'car', dist: 90}, {type: 'foot', dist: 7}] 

const distanceByType = trip.reduce((out, curr) => {
    const { type, dist } = curr;
    if (out[type]) {
        out[type] += dist;
    } else {
        out[type] = dist;
    }
    return out;
}, {});

// distanceByType = {car: 132, foot: 10, flight: 212};

So here, we're taking in an array, but returning an object of sums, instead of just a single one.

Here we're beginning to see the essence of what a reducer really is:

A reducer is a transformer

It takes in an array and transforms it into something else.

Thinking of it in this way not only helps me understand what reduce does but also helps me realize when I should be using it.

  • Have an array of users but want to output a string like, Mike, Becka and 3 others will be attending? A reducer is great for that!

  • Have an array of articles and want an object with them keyed by category? A reducer is great for that!

The use cases go on and on.

Go forth and Array.reduce()!

I really hope that helps and would love to clarify things further in the comments if I can.

Got a use case for reduce that you love? Comment below and I'll add it to the article šŸš€

Discussion

pic
Editor guide
Collapse
dance2die profile image
Sung M. Kim

My favorite is a pipe method.

const pipeOnce = (fn1, fn2) => (args) => (fn2(fn1(args)));
const pipe = (...ops) => ops.reduce(pipeOnce);
// OR const pipe = (...ops) 
//     => ops.reduce((fn1, fn2) => (args) => (fn2(fn1(args))));

const addTwo = a => a + 2;
const mulTwo = a => a * 2;

const addTwoMulTwo = pipe(addTwo, mulTwo);
console.log(addTwoMulTwo(1));  // (1 + 2) * 2 => 6
console.log(addTwoMulTwo(2));  // (2 + 2) * 2 => 8
console.log(addTwoMulTwo(3));  // (3 + 2) * 2 => 10

It's just amazing that you can not only pass an array of objects, you can pass an array of functions, as a function is a first-class citizen in JavaScript.

And also, C# has a reduce method named Aggregate, which I think reflects more of what it does.

Collapse
krofdrakula profile image
Klemen Slavič

I like to use reduce when transforming lists, like creating a Map from an array based on a key:

const userData = [{ id: 1, name: 'A' }, { id: 2, name: 'B' }];

// a general-purpose array-to-map utility
const arrayToMap = (list, idMapper) =>
  list.reduce(
    (map, next) => {
      map.set(idMapper(next), next);
      return map;
    },
    new Map()
  );

console.log(arrayToMap(userData, user => user.id));
Collapse
sadarshannaiynar profile image
Adarsh

Nice post. I have seen people using map to do something that can be easily done by reduce. But somehow I felt some developers don't know that reduce exists in the prototype of Array or they are hesitant to switch to reduce.

Collapse
dienand profile image
DieNand

Nice, I've used it here and there myself without fully understanding it. A good clear explanation, thanks!

Collapse
nikolicstjepan profile image
Nikolić Stjepan

Yea, reduce is currently underrated for sure.
Great article, thanks Nicky for sharing!