The `reduce()` method on JavaScript arrays executes a "reducer" function on every element of the array in order, passing the return value from the previous reducer call to the next reducer call. The `reduce()` function is a common cause of confusion, but it can also make your code much more readable when combined with other functional programming abstractions. Here are 4 common examples and 1 not-so-common example that demonstrate how to use `reduce()`.

## Summing an Array of Numbers

Most `reduce()` tutorials start with this example: given an array of numbers `[1, 3, 5, 7]`, calculate the sum. Here's how you might sum up an array with a plain old `for` loop.

``````function sum(arr) {
let sum = 0;
for (const val of arr) {
sum += val;
}
return sum;
}

sum([1, 3, 5, 7]); // 16``````

Here's an equivalent example using `reduce()`:

``````function sum(arr) {
const reducer = (sum, val) => sum + val;
const initialValue = 0;
return arr.reduce(reducer, initialValue);
}

sum([1, 3, 5, 7]); // 16``````

The `reduce()` function's first 2 parameters are a function `reducer()` and an arbitrary `initialValue`. JavaScript then calls the `reducer()` on each element of the array with the accumulator value as the first parameter. The accumulator starts as `initialValue`, and then JavaScript uses the return value of each `reduce()` call as the new accumulator.

Talk is cheap, show me the code. So here's a quick example of how you might implement a simplified `reduce()` function using `for` loops.

``````function reduce(arr, reducer, initialValue) {
let accumulator = initialValue;
for (const val of array) {
accumulator = reducer(accumulator, val);
}
return accumulator;
}``````

## Summing an Array of Numeric Properties

The `reduce()` function by itself is often more confusing than helpful. If all you need to do is sum an array of numbers, you might be better off using a `for` loop. But, when combined with other array methods like `filter()` and `map()`, `reduce()` starts looking more appealing.

For example, suppose you have an array of line items, and you want to calculate the sum of each line item's `total` property.

``````const lineItems = [
{ description: 'Eggs (Dozen)', quantity: 1, price: 3, total: 3 },
{ description: 'Cheese', quantity: 0.5, price: 5, total: 2.5 },
{ description: 'Butter', quantity: 2, price: 6, total: 12 }
];``````

Here's one way to add up the line items `total` using `reduce()`:

``lineItems.reduce((sum, li) => sum + li.total, 0); // 17.5``

This works, but is less composable. A better alternative is to first `map()` to get the `total`.

``lineItems.map(li => li.total).reduce((sum, val) => sum + val, 0);``

Why is this second approach better? Because you can abstract out the reducer into a function `sum()`, and reuse it wherever you need to sum up an array.

``````// Sum the totals
lineItems.map(li => li.total).reduce(sumReducer, 0);

// Sum the quantities using the same reducer
lineItems.map(li => li.quantity).reduce(sumReducer, 0);

function sumReducer(sum, val) {
return sum + val;
}``````

This is important because, while you think `sumReducer()` will never change, it will. For example, the above code doesn't account for the fact that `0.1 + 0.2 !== 0.3` in JavaScript. This is a common mistake when calculating prices in an interpretted language. Binary floating points are weird. So you actually need to round:

``````const { round } = require('lodash');

function sumReducer(sum, val) {
// Round to 2 decimal places.
return _.round(sum + val, 2);
}``````

`reduce()` makes it easy to reuse logic like `sumReducer()` throughout your app using function chaining. So you can change your logic once rather than searching through every `for` loop in your app.

## Find the Maximum Value

While `reduce()` is often used for summing, it doesn't have to be. The `accumulator` can be any value: number, `null`, `undefined`, array, POJO, even a promise.

For example, suppose you have an array of JavaScript dates, and you want to find the most recent date.

``````const dates = [
'2019/06/01',
'2018/06/01',
'2019/09/01', // This is the most recent date, but how to find it?
'2018/09/01'
].map(v => new Date(v));``````

One approach is to sort the array and take the last element in the sorted array. That works, but isn't as efficient as it could be, and sorting an array of dates in JavaScript is non-trivial.

Instead, you can use `reduce()` and make your reducer return the most recent date found so far.

``````// This works because you can compare JavaScript dates using `>` and `<`.
// So `a > b` if and only if `a` is after `b`.
const maxDate = dates.reduce((max, d) => d > max ? d : max, dates);``````

## Grouping Values

Given an array of objects with an `age` property:

``````const characters = [
{ name: 'Jean-Luc Picard', age: 59 },
{ name: 'Will Riker', age: 29 },
{ name: 'Deanna Troi', age: 29 }
];``````

How do you return a map that contains how many characters have a given `age`? For example, the correct output on the above array would be `{ 29: 2, 59: 1 }`.

Here's how you can do that with `reduce()`.

``````// Start with an empty object, increment `map[age]` for each element
// of the array.
const reducer = (map, val) => {
if (map[val] == null) {
map[val] = 1;
} else {
++map[val];
}
return map;
};
characters.map(char => char.age).reduce(reducer, {});``````

## Bonus: Promise Chaining

Suppose you have an array of async functions that you want to execute in series. There is a non-standard `promise.series` function for this, but you can also do this with `reduce()`.

``````const functions = [
async function() { return 1; },
async function() { return 2; },
async function() { return 3; }
];

// Chain the function calls in order, starting with an empty promise.
// In the end, `res` is equivalent to
// `Promise.resolve().then(fn1).then(fn2).then(fn3)`
const res = await functions.
reduce((promise, fn) => promise.then(fn), Promise.resolve());
res; // 3``````

## Moving On

The `reduce()` function is a powerful tool. By abstracting out filters and reducers, you can consolidate common tasks like "summing an array of numbers" into a separate function for easier refactoring and DRY-er code.

Found a typo or error? Open up a pull request! This post is available as markdown on Github