Mastering Array.reduce()

Hard

Array.reduce() is the most powerful and versatile array method. It transforms an array into any value type: number, string, object, array, or even another function. Mastering reduce patterns is essential for functional programming and many interview problems. This concept covers common patterns: sum, groupBy, flatten, pipe, and count.

Interactive Visualization

mutation Methods

1
2
3

Key Points

  • reduce((accumulator, current) => newAccumulator, initialValue)
  • Can transform array into any type (number, object, array, etc.)
  • Always provide initial value to avoid bugs
  • Common patterns: sum, groupBy, flatten, pipe, count
  • Can replace map+filter chains for single pass
  • More powerful but less readable than specialized methods

Code Examples

Sum and Product

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

// Sum
const sum = nums.reduce((acc, n) => acc + n, 0);
console.log(sum);  // 15

// Product
const product = nums.reduce((acc, n) => acc * n, 1);
console.log(product);  // 120

// Maximum
const max = nums.reduce((acc, n) => n > acc ? n : acc, -Infinity);
console.log(max);  // 5

// Initial value is crucial!

Basic reduce patterns. Always provide initial value.

groupBy Pattern

const users = [
  { name: 'Alice', city: 'NYC' },
  { name: 'Bob', city: 'LA' },
  { name: 'Carol', city: 'NYC' }
];

// Group by city
const grouped = users.reduce((acc, user) => {
  const key = user.city;
  if (!acc[key]) {
    acc[key] = [];
  }
  acc[key].push(user);
  return acc;
}, {});

console.log(grouped);
// {
//   NYC: [{ name: 'Alice', city: 'NYC' }, { name: 'Carol', city: 'NYC' }],
//   LA: [{ name: 'Bob', city: 'LA' }]
// }

Most common reduce pattern: group array elements by a key.

Flatten Array

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

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

// Or with spread
const flat2 = nested.reduce((acc, arr) => [...acc, ...arr], []);

// Deep flatten (recursive)
const deepNested = [1, [2, [3, 4]], 5];

function deepFlatten(arr) {
  return arr.reduce((acc, val) => 
    acc.concat(Array.isArray(val) ? deepFlatten(val) : val),
    []
  );
}

console.log(deepFlatten(deepNested));  // [1, 2, 3, 4, 5]

Flatten nested arrays. For simple cases, use arr.flat() instead.

Count Occurrences

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

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

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

// With nullish coalescing
const counts2 = fruits.reduce((acc, fruit) => {
  acc[fruit] = (acc[fruit] ?? 0) + 1;
  return acc;
}, {});

Count frequency of elements. Very common interview pattern.

Pipeline (Function Composition)

// Compose functions left to right
const pipe = (...fns) => x => fns.reduce((v, f) => f(v), x);

// Usage
const add5 = x => x + 5;
const multiply2 = x => x * 2;
const toString = x => String(x);

const transform = pipe(add5, multiply2, toString);

console.log(transform(3));  // "16"
// (3 + 5) * 2 = 16 -> "16"

// Equivalent to: toString(multiply2(add5(3)))

Advanced: use reduce for function composition and pipelines.

Common Mistakes

  • Forgetting initial value (causes TypeError on empty array)
  • Not returning accumulator in callback
  • Using reduce when map/filter/find would be clearer
  • Mutating the accumulator object incorrectly

Interview Tips

  • Always provide initial value
  • Know common patterns: sum, groupBy, flatten, count
  • Be able to implement groupBy from scratch
  • Understand reduce can create any data type