Course outline · 0% complete

0/29 lessons0%

Course overview →

reduce: fold to a single value

lesson 7-3 · ~10 min · 24/29

One value out

map and filter give arrays back. reduce combines all the items into one result: a total, a maximum, a combined string.

const nums = [1, 2, 3, 4];
const sum = nums.reduce((total, n) => total + n, 0);   // 10

Two arguments to reduce:

  1. An arrow taking (accumulator, item). The accumulator is the running result so far. Whatever the arrow returns becomes the accumulator for the next item.
  2. The starting value for the accumulator (0 here).

Trace the sum: start 0, then 0+1=1, 1+2=3, 3+3=6, 6+4=10. It is exactly the sum loop from lesson 4-3, with the machinery folded in. If reduce feels dense, write the loop first and translate. Both are correct, and reduce is the one you will read constantly in other people's code.

nums = [1, 2, 3, 4] with start 00start1+ 13+ 26+ 310+ 4Each box is the accumulator after one item is folded in.The last box is what reduce returns, one value from four.
A reduce folding four numbers into one total. The accumulator starts at the given value and each step feeds its result into the next.

Summing and maximizing with the same method

Two reduces over one array. The first combines with addition and the second combines with Math.max, which shows that the combining step can be any function of two values.

const nums = [7, 2, 9, 4];

const sum = nums.reduce((total, n) => total + n, 0);
console.log(sum);

const max = nums.reduce((best, n) => Math.max(best, n), nums[0]);
console.log(max);

Output

22
9

The sum begins at 0 and folds each number in, reaching 22. The maximum begins at nums[0], which is 7, and each step keeps the larger of the running best and the current item using Math.max from lesson 1-2.

Comparing the two lines side by side is the fastest way to internalize reduce. Only two things changed: the operation inside the arrow and the starting value. Everything else about the mechanism is identical, which is why one method can express totals, maximums, counts, and joined strings.

Totaling a cart with reduce

The sum pattern applied to prices. This is the same job the hand-written loop did in lesson 4-3, now as a single expression.

const cart = [3, 12.5, 7];

const total = cart.reduce((total, price) => total + price, 0);
console.log(total);

Output

22.5

The shape to memorize is cart.reduce((total, price) => total + price, 0), and the easiest way to read it is to name its three parts. The first parameter is the running result, the second is the current item, and the 0 at the end is where the running result begins.

Starting at 0 is what makes an empty cart total 0 instead of throwing. That is a real advantage over the loop version, where forgetting to initialize the accumulator produces undefined and then NaN.

Reducing to the longest word

Not every reduce produces a number. Here the accumulator holds a word, specifically the longest one seen so far, and each step returns whichever of the two candidates is longer.

const words = ["map", "filter", "reduce", "of"];

const longest = words.reduce((best, w) => (w.length > best.length ? w : best), words[0]);
console.log(longest);

Output

filter

The arrow compares lengths but returns a word, using the conditional operator from lesson 3-1: w.length > best.length ? w : best. That asymmetry between what is compared and what is returned is what makes this pattern worth learning.

The result is filter rather than reduce, even though both have six letters, because the comparison uses a strict >. When lengths tie, best wins and the earlier word keeps the title.

Starting from words[0] is the same trick the maximum used earlier: seed the accumulator with a real item so the first comparison has something valid to work against.

The product pattern

Multiplying an array together is summing with two changes, a * in place of the + and a starting value of 1:

const nums = [2, 3, 4];
const product = nums.reduce((acc, n) => acc * n, 1);
console.log(product);

Output

24

Tracing the accumulator makes it concrete. It starts at 1, then becomes 1 × 2 = 2, then 2 × 3 = 6, then 6 × 4 = 24.

The starting value has to be 1 here, and that is the interesting part. Starting at 0 would make every product zero, because 0 × 2 is 0 and nothing recovers from it. Each combining operation has a value that leaves its input unchanged, which is 0 for addition and 1 for multiplication, and that is the value a reduce should start from.

GoalCombining arrowStart value
sum(acc, n) => acc + n0
product(acc, n) => acc * n1
maximum(acc, n) => Math.max(acc, n)nums[0]
joined text(acc, s) => acc + s""