The reduce method is often ignored by JavaScript developers—even if they have a few years of experience. If you have a good grasp of the map, filter, and forEach methods, you may be able to get by for a while without learning the reduce method.

Eventually, I ran into a problem and every Stack Overflow answer I found used the reduce method. I finally buckled and decided to learn it. And I’m so glad I did!

Note: View a video overview of the reduce method on my YouTube channel.

What is the reduce method?

The reduce method takes in an array and returns any single value.

Map, ForEach, or Filter, but with Superpowers!

Reduce finally “clicked” when I realized that it’s like the other higher-order array methods, but with superpowers! So what superpowers does reduce have?

Here are at least 3:

  1. It can return any single value, not just an array (like map and filter).
  2. It gives you access to the accumulated value at each loop. You always return this accumulated value so the next loop has access to it. The final result is the accumulated value after the last loop.
  3. You can run checks inside the loop, reducing the number of loops you need to run (you can often replace a filter and a map with a single reduce).

Let’s take a simple problem and solve it without and with the reduce method. Here’s how you might add up all numbers less than 4 in the numbers array using only filter and forEach.

const numbers = [1, 2, 3, 4, 5];
let sum = 0;
numbers.filter((num) => num < 4).forEach((num) => (sum += num));

While not wrong, it’s a bit messy to declare a variable and then mutate it inside the array loops. Additionally, because we’re using both the filter and the forEach method, it takes two loops to solve the problem. You could obviously compress it a bit more and do the check inside the forEach loop, but you still have that pesky variable declaration.

How might you do the same thing with reduce?

const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((acc, num) => (num > 4 ? acc : (acc += num)), 0);

Let’s walk through that very slowly.

How to Use the Reduce Method

The reduce method takes in a callback function and an initial value. The callback function takes in two parameters: (1) the accumulated value and (2) the current value. The initial value is the starting value for the accumulated value.

Step 1: Add a callback function and initial value

The reduce method takes two items: a callback function and an initial value.

const sum = numbers.reduce(() => {}, 0);

I’ve written the callback function as an arrow function and started with the initial value of 0. Generally speaking, you should set the initial value to whatever type of value you want to return. For example, if you want to return a number, set the initial value to 0. If you want to return an array or object, set the initial value to an empty array or object.

Note: While you don’t technically have to pass along an initial value, I always do. If you do not provide an initial value, the first item in your array is passed in as the starting point for your acc. Depending on your loop, this can produce inaccurate results.

Step 2: Add the accumulated value and array item

The callback function takes two important parameters: (1) the accumulated value and (2) the item in the array (these must be the first and second parameters you pass in). The accumulated value is the value that is returned after each loop. The item in the array is the current item in the array.

const sum = numbers.reduce((acc, num) => {}, 0);

The reduce method does take in a third and fourth parameter, but I don’t use them often. The third parameter is the index of the current item in the array. The fourth parameter is the array itself. So in all, the reduce method can take in four parameters:

  1. The accumulated value (required)
  2. The current item in the array (required)
  3. The index of the current item in the array (optional)
  4. The array itself (optional)

Note: I usually call the first parameter, the accumulated value, `acc` and the second parameter, the item I’m looping over in the array, a name that makes sense for the array, like `num` for “number.”

Step 3: Return the accumulated value

Start by returning the accumulated value as the last action of each reduce loop. This passes along the accumulated value to each loop and then returns the full accumulated value after reduce has looped through every item in your array.

const sum = numbers.reduce((acc, num) => {
  return acc;
}, 0);

Step 4: Add your logic

Finally, add your logic to each loop. In this example, I’ve set up a guard clause to check if the number is less than 4. If it is, it skips that item in the loop and passes on the accumulated value up to that point to the next loop. If the current number is less than 4, it adds the number to the accumulated value and passes that along to the next loop.

const sum = numbers.reduce((acc, num) => {
  if (num > 4) {
    return;
  }
  return (acc += num);
}, 0);

We can compress this a bit more by using a ternary and an implicit return. Nothing like a nice one-liner!

const sum = numbers.reduce((acc, num) => (num > 4 ? acc : (acc += num)), 0);

Understanding each reduce loop

If we console.log the reduce method, we can see how it works.

const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((acc, num) => {
  console.log(`acc: ${acc}, num: ${num}`);
  return num > 4 ? acc : (acc += num);
}, 0);

// This ☝️ will print the following:
// acc: 0, num: 1
// acc: 1, num: 2
// acc: 3, num: 3
// acc: 6, num: 4
// acc: 6, num: 5

By way of explanation,

  • During the first loop, the accumulated value starts with the initial value of 0 (because we passed that in as the initial value) and the value of the current array item is 1 (because that’s the first number in the array)
  • During the second loop, the accumulated value is 1 and the current value is 2
  • During the third loop, the accumulated value is 3 and the current value is 3
  • During the fourth loop, the accumulated value is 6 and the current value is 4 (because 4 is not less than 4, the accumulated value is not changed)
  • During the fifth loop, the accumulated value is 6 and the current value is 5 (because 5 is not less than 4, the accumulated value is not changed)

A few examples

Here are a few examples of how and why you might use the reduce method.

Example 1: Group an array of objects by a property

Because you can return an object from a reduce method (superpower #1), you can use it to group an array of objects by a property.

const people = [
  { name: "John", age: 20 },
  { name: "Jane", age: 25 },
  { name: "Jack", age: 20 },
  { name: "Jill", age: 30 },
];
const peepsByAge = people.reduce((acc, person) => {
  const key = person.age;
  const value = acc[key] || [];
  return { ...acc, [key]: [...value, person] };
}, {});

// This ☝️ will return the following:
// {
//   20: [{ name: 'John', age: 20 }, { name: 'Jack', age: 20 }],
//   25: [{ name: 'Jane', age: 25 }],
//   30: [{ name: 'Jill', age: 30 }]
// }

Note: During each loop, it grabs the age of the person as a key and first checks if the current accumulated object (which started as an emtpy object) has that key. If it does, it spreads in the value of that key and then adds the current person object to that value of the accumulated object.

Example 2: Count the number of times a value appears in an array

You can use reduce to count the number of times a value appears in an array.

const numbers = [1, 2, 3, 4, 5, 1, 2, 3, 4, 5];
const count = numbers.reduce((acc, num) => {
  const key = num;
  const value = acc[key] || 0;
  return { ...acc, [key]: value + 1 };
}, {});

// This ☝️ will return the following:
// {
//   1: 2,
//   2: 2,
//   3: 2,
//   4: 2,
//   5: 2
// }

Note: Like the first example, during each loop, we identify the current key, check if it exists on the accumulated object, and then update the accumulated object. When it finishes looping over the array, the reduce method returns the accumulated object.

Example 3: Remove duplicate values from an array

You can use reduce to remove duplicate values from an array.

const numbers = [1, 2, 3, 4, 5, 1, 2, 3, 4, 5];
const unique = numbers.reduce(
  (acc, num) => (acc.indexOf(num) > -1 ? acc : [...acc, num]),
  []
);

// This ☝️ will return the following:
// [1, 2, 3, 4, 5]

Note: During each loop, it checks if the number exists in the accumulated array at that point in the loop. If it does exist, it passes on the accumulated array to the next loop. Otherwise, it spreads in the contents of the current accumulated array and then adds the num to that array. That new accumulated array is passed on to the next loop until the reduce loop finishes looping through each item in the array, at which point, it returns the final accumulated array.