Reducing Arrays

The reduce method combines the elements of an array into a single value. It calls a function with a running result, called the accumulator, and each element in turn. It is a versatile array method. You can implement map, filter, and many other operations with it.

Basic Usage: Summing Numbers

const numbers = [1, 2, 3, 4, 5];

const sum = numbers.reduce((accumulator, current) => {
  return accumulator + current;
}, 0);

console.log(sum);  // 15

The reduce callback receives:

  • accumulator: the running result (starts as the initial value)
  • current: the current element being processed

The second argument to reduce (here 0) is the initial value.

How Reduce Works Step by Step

const numbers = [1, 2, 3, 4, 5];

numbers.reduce((acc, cur) => acc + cur, 0);

// Step 1: acc = 0,  cur = 1  → returns 1
// Step 2: acc = 1,  cur = 2  → returns 3
// Step 3: acc = 3,  cur = 3  → returns 6
// Step 4: acc = 6,  cur = 4  → returns 10
// Step 5: acc = 10, cur = 5  → returns 15

In the first step, the accumulator is the initial value 0. The value each step returns becomes the accumulator for the next step.

The Importance of Initial Value

Always provide an initial value. Without it, reduce uses the first element as the initial accumulator, which throws a TypeError if the array is empty:

const numbers = [1, 2, 3];

// Without initial value - works but risky
const sum1 = numbers.reduce((acc, cur) => acc + cur);
console.log(sum1); // 6

// Empty array without initial value - throws error!
const empty = [];
// empty.reduce((acc, cur) => acc + cur); // TypeError!

// With initial value - always safe
const sum2 = empty.reduce((acc, cur) => acc + cur, 0);
console.log(sum2); // 0

Finding Maximum/Minimum

const numbers = [3, 1, 4, 1, 5, 9, 2, 6];

const max = numbers.reduce((acc, cur) => (cur > acc ? cur : acc), -Infinity);
console.log(max); // 9

const min = numbers.reduce((acc, cur) => (cur < acc ? cur : acc), Infinity);
console.log(min); // 1

For simple min/max, Math.max(...numbers) is clearer.

Counting Occurrences

Build an object that counts how many times each value appears:

const fruits = ["apple", "banana", "apple", "orange", "banana", "apple"];

const counts = fruits.reduce((acc, fruit) => {
  acc[fruit] = (acc[fruit] || 0) + 1;
  return acc;
}, {});

console.log(counts); // { apple: 3, banana: 2, orange: 1 }

Grouping Data

Group objects by a property:

const people = [
  { name: "Alice", department: "Engineering" },
  { name: "Bob", department: "Sales" },
  { name: "Charlie", department: "Engineering" },
  { name: "Diana", department: "Sales" },
];

const byDepartment = people.reduce((acc, person) => {
  const dept = person.department;
  if (!acc[dept]) {
    acc[dept] = [];
  }
  acc[dept].push(person);
  return acc;
}, {});

console.log(byDepartment);
// {
//   Engineering: [{ name: 'Alice', ... }, { name: 'Charlie', ... }],
//   Sales: [{ name: 'Bob', ... }, { name: 'Diana', ... }]
// }

Flattening Arrays

const nested = [
  [1, 2],
  [3, 4],
  [5, 6],
];

const flat = nested.reduce((acc, cur) => acc.concat(cur), []);
console.log(flat); // [1, 2, 3, 4, 5, 6]

Note: For flattening, the flat method (covered later) is more readable.

Building a Pipeline

Reduce can apply a series of functions:

const pipeline = [(x) => x + 1, (x) => x * 2, (x) => x - 3];

const result = pipeline.reduce((acc, fn) => fn(acc), 5);
// (5 + 1) = 6, then (6 * 2) = 12, then (12 - 3) = 9
console.log(result); // 9

This is the pattern that function composition libraries are built on.