Understanding the Reduce Method

The reduce() method is one of JavaScript’s most powerful array methods. It executes a reducer function on each element of an array, resulting in a single output value. Unlike map() which returns a new array, reduce() returns a single accumulated value.

Key Point: The reduce() method is perfect for operations that need to combine array elements into a single result, such as summing values, flattening arrays, or calculating averages.

Reduce Method Syntax

Basic Syntax

const result = array.reduce(function(accumulator, currentValue, index, array) {
  // return updated accumulator
}, initialValue);
  • accumulator: Accumulates the callback’s return values
  • currentValue: The current element being processed
  • index: The index of the current element (optional)
  • array: The array being traversed (optional)
  • initialValue: Value to use as the first accumulator (optional)

Basic Reduce Examples

Summing Array Elements

const numbers = [2, 4, 6, 8];

// Without initial value
const sum = numbers.reduce(function(acc, curr) {
  return acc + curr;
});
console.log(sum); // 20

// With initial value
const sumWithInitial = numbers.reduce(function(acc, curr) {
  return acc + curr;
}, 10);
console.log(sumWithInitial); // 30 (10 + 2 + 4 + 6 + 8)

// Using arrow function
const sumArrow = numbers.reduce((acc, curr) => acc + curr, 0);
console.log(sumArrow); // 20

Calculating Product

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

// Calculate product
const product = numbers.reduce((acc, curr) => acc * curr, 1);
console.log(product); // 120 (2 * 3 * 4 * 5)

Flattening Arrays with Reduce

One of the most common uses of reduce() is to flatten multidimensional arrays into a single-dimensional array.

Flattening a 2D Array

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

// Flatten using reduce
const flatArray = twoDArray.reduce((acc, curr) => {
  return acc.concat(curr);
}, []);

console.log(flatArray); // [1, 2, 3, 4, 5, 6]

// Using spread operator (more concise)
const flatArraySpread = twoDArray.reduce((acc, curr) => [...acc, ...curr], []);
console.log(flatArraySpread); // [1, 2, 3, 4, 5, 6]

Flattening Arrays with Mixed Depths

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

// Flatten one level
const flatOneLevel = mixedArray.reduce((acc, curr) => acc.concat(curr), []);
console.log(flatOneLevel); // [1, 2, 3, 4, [5, 6], 7]

// Recursive flattening function
function flattenDeep(arr) {
  return arr.reduce((acc, curr) => {
    return Array.isArray(curr) ? acc.concat(flattenDeep(curr)) : acc.concat(curr);
  }, []);
}

const completelyFlat = flattenDeep(mixedArray);
console.log(completelyFlat); // [1, 2, 3, 4, 5, 6, 7]

Working with Object Arrays

Summing Object Properties

const employees = [
  { name: "John", salary: 50000 },
  { name: "Jane", salary: 60000 },
  { name: "Bob", salary: 55000 }
];

// Calculate total salaries
const totalSalary = employees.reduce((acc, curr) => {
  return acc + curr.salary;
}, 0);

console.log(totalSalary); // 165000

// Calculate average salary
const averageSalary = employees.reduce((acc, curr, index, array) => {
  acc += curr.salary;
  return index === array.length - 1 ? acc / array.length : acc;
}, 0);

console.log(averageSalary); // 55000

Reduce vs ReduceRight

Reduce vs ReduceRight Comparison

Feature reduce() reduceRight()
Direction Left to right Right to left
Starting point First element Last element
Use case Most common operations Right-associative operations

ReduceRight Example

const numbers = [2, 3, 4];

// Exponentiation: 2^(3^4)
const resultRight = numbers.reduceRight((acc, curr) => Math.pow(curr, acc));
console.log(resultRight); // 2.4178516392292583e+24

// Compare with regular reduce: (2^3)^4
const resultLeft = numbers.reduce((acc, curr) => Math.pow(acc, curr));
console.log(resultLeft); // 4096

Common Questions Answered

Finding Maximum Value

const numbers = [12, 45, 7, 32, 89, 23];

// Find maximum value
const max = numbers.reduce((acc, curr) => {
  return curr > acc ? curr : acc;
}, numbers[0]);

console.log(max); // 89

Grouping Objects by Property

const people = [
  { name: "Alice", age: 25 },
  { name: "Bob", age: 30 },
  { name: "Charlie", age: 25 },
  { name: "David", age: 30 }
];

// Group by age
const groupedByAge = people.reduce((acc, curr) => {
  const age = curr.age;
  if (!acc[age]) {
    acc[age] = [];
  }
  acc[age].push(curr);
  return acc;
}, {});

console.log(groupedByAge);
// {
//   25: [{ name: "Alice", age: 25 }, { name: "Charlie", age: 25 }],
//   30: [{ name: "Bob", age: 30 }, { name: "David", age: 30 }]
// }

Best Practices

  • Always provide an initial value for predictable results
  • Use descriptive variable names for accumulator and currentValue
  • Consider using the spread operator for array concatenation
  • For complex transformations, break the logic into separate functions
  • Remember that reduceRight processes arrays from right to left