reduce: Boil It Down to One Value

Grade 10, page 7 of 12. A two-minute read.

And now, the most powerful (and most confusing) method of all: reduce. It takes a whole array and reduces it down to a single value. That value could be a total, a maximum, a count, a string, an object... anything.

Here's the classic example, adding up numbers:

JavaScript
const numbers = [5, 10, 15, 20];

const total = numbers.reduce((runningTotal, n) => runningTotal + n, 0);
console.log(total);

It prints

50

reduce takes two arguments:

  1. A callback that receives the accumulator (the running result so far) and the current item, and returns the new accumulator.
  2. A starting value for the accumulator (here, 0).

This is exactly the accumulator pattern from Grade 5, packed into a method. Let's trace it step by step:

StepAccumulator (before)Current itemCallback returns
10 (the starting value)50 + 5 = 5
25105 + 10 = 15
3151515 + 15 = 30
4302030 + 20 = 50

After the last item, the final accumulator (50) is the result.

Think of it like thisThe snowball

Picture a snowball rolling down a hill. It starts small (the starting value). Each time it rolls over a patch of snow (an item), it picks some up and gets bigger (the callback decides how). At the bottom of the hill, you've got one big snowball (the result).

More reduce recipes

Finding the biggest:

JavaScript
const temps = [28, 35, 31, 29];
const hottest = temps.reduce((max, t) => (t > max ? t : max), temps[0]);
console.log(hottest);

It prints

35

Totaling a property:

JavaScript
const cart = [
  { item: "rice", price: 120, qty: 1 },
  { item: "eggs", price: 2, qty: 12 },
  { item: "milk", price: 15, qty: 2 },
];

const total = cart.reduce((sum, line) => sum + line.price * line.qty, 0);
console.log(`Cart total: $${total}`);

It prints

Cart total: $174

Counting things into an object:

JavaScript
const votes = ["burger", "omelet", "burger", "pasta", "burger", "omelet"];

const tally = votes.reduce((counts, vote) => {
  counts[vote] = (counts[vote] || 0) + 1;
  return counts;
}, {});

console.log(tally);

It prints

{ burger: 3, omelet: 2, pasta: 1 }

Here the accumulator starts as an empty object {}. For each vote, we add one to that food's count. (The counts[vote] || 0 part means "use the current count, or 0 if there isn't one yet." Remember: undefined is falsy, so || falls back to 0.) The fried rice has won. Democracy has spoken.

Watch outAlways give reduce a starting value

You're technically allowed to leave out the starting value, in which case reduce uses the first item. But if the array is empty, it crashes:

JavaScript
const empty = [];
const total = empty.reduce((sum, n) => sum + n);

It stops with an error

Uncaught TypeError: Reduce of empty array with no initial value

With a starting value, [].reduce((sum, n) => sum + n, 0) safely gives 0. Always include one!

TipDon't force it

reduce can do almost anything, which makes it tempting to use everywhere. But for a lot of tasks, map, filter or a simple loop is much easier to read. Use reduce when you're truly boiling a list down into one thing, like a total or a tally.

Reading is step one

CurlyScript turns these notes into a game: short questions, an explanation after every answer, and a test at the end of each grade. Free, with nothing to sign up for.

Start learning