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.