reduce()

The JavaScript reduce() method runs a function on each element of the array from left to right (first to last), resulting in a single (reduced to) value. Making it a good choice for calculating totals, accumulating values, or transforming arrays into different data structures.

The reduceRight() method is also available for processing an array from right to left.

Syntax

const result = array.reduce(function(accumulator, currentValue, index, array) {
  // return accumulated value
}, initialValue);

Parameters:

  • function: Function to run on each element of the array, taking four possible arguments:
    • accumulator: The current total (accumulated) value, returned by the previous callback function call.
    • currentValue: The current array element being processed.
    • index (optional): The index position of the current array element.
    • array (optional): The original array the reduce() method was called upon.
  • initialValue (optional): An initial starting value for the accumulator.

Basic usage

Let's start with a simple example of calculating the total price of pizza orders:

const orders = [
  { name: 'Margherita', price: 10 },
  { name: 'Pepperoni', price: 13 },
  { name: 'Supreme', price: 15 }
];

const totalPrice = orders.reduce((total, pizza) => {
  return total + pizza.price;
}, 0);

console.log(totalPrice);
// Output: 38

In this example, the total is the accumulated value. We do this in the return statement by adding the pizza.price to the current total for each array value.

Using the index parameter

The index parameter can be useful for tracking progress or creating numbered lists:

const pizzaToppings = ['Cheese', 'Pepperoni', 'Mushrooms', 'Olives'];

const numberedList = pizzaToppings.reduce((list, topping, index) => {
  return list + `${index + 1}. ${topping}\n`;
}, '');

console.log(numberedList);
// Output:
// 1. Cheese
// 2. Pepperoni
// 3. Mushrooms
// 4. Olives

Using the array parameter

The array parameter provides reference to the original array:

const pizzaOrders = [
  { name: 'Margherita', price: 10, quantity: 2 },
  { name: 'Pepperoni', price: 12, quantity: 1 },
  { name: 'Supreme', price: 15, quantity: 3 }
];

const orderSummary = pizzaOrders.reduce((summary, order, index, array) => {
  const isLast = index === array.length - 1;
  return summary + `${order.name} (${order.quantity}x)${isLast ? '' : ', '}`;
}, 'Order Summary: ');

console.log(orderSummary);
// Output: Order Summary: Margherita (2x), Pepperoni (1x), Supreme (3x)

This example checks the length of the original array, and stores it into the isLast variable. This is then used to only add a comma when the item is not the last one in the list.

Working with objects in arrays

The reduce() method is also useful when working with arrays of objects:

const pizzaMenu = [
  { name: 'Margherita', price: 10, category: 'Standard' },
  { name: 'Pepperoni', price: 12, category: 'Standard' },
  { name: 'Supreme', price: 15, category: 'Specialty' },
  { name: 'Meat feast', price: 13, category: 'Specialty' }
];

// Group pizzas by category
const menuByCategory = pizzaMenu.reduce((categories, pizza) => {
  if (!categories[pizza.category]) {
    categories[pizza.category] = [];
  }
  categories[pizza.category].push(pizza);
  return categories;
}, {});

console.log(menuByCategory);

/* Output:
{
  "Standard": [
    {
      "name": "Margherita",
      "price": 10,
      "category": "Standard"
    },
    {
      "name": "Pepperoni",
      "price": 12,
      "category": "Standard"
    }
  ],
  "Specialty": [
    {
      "name": "Supreme",
      "price": 15,
      "category": "Specialty"
    },
    {
      "name": "Meat feast",
      "price": 13,
      "category": "Specialty"
    }
  ]
}
*/

Chaining reduce()

The reduce() method can be combined with other array methods for powerful data transformations:

const pizzaOrders = [
  { name: 'Margherita', price: 10, quantity: 2 },
  { name: 'Pepperoni', price: 12, quantity: 1 },
  { name: 'Supreme', price: 15, quantity: 3 }
];

// Calculate total value of orders over $20
const highValueOrders = pizzaOrders
  .filter(order => order.price * order.quantity > 20)
  .reduce((total, order) => total + (order.price * order.quantity), 0);

console.log(highValueOrders);
// Output: 45 (Supreme: 15 * 3 = 45)

Nesting the reduce() method

When working with nested data, reduce() can be used at multiple levels:

const pizzaStores = [
  {
    name: "Store 1",
    orders: [
      { pizza: "Margherita", quantity: 2 },
      { pizza: "Pepperoni", quantity: 1 }
    ]
  },
  {
    name: "Store 2",
    orders: [
      { pizza: "Margherita", quantity: 1 },
      { pizza: "Supreme", quantity: 3 }
    ]
  }
];

// Calculate total pizzas sold across all stores
const totalPizzasSold = pizzaStores.reduce((total, store) => {
  const storeTotal = store.orders.reduce((storeSum, order) => {
    return storeSum + order.quantity;
  }, 0);
  return total + storeTotal;
}, 0);

console.log(totalPizzasSold);
// Output: 7

Practical example: creating a progress bar

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

const progressBar = progress.reduce((bar, step, index, array) => {
  const position = index + 1;
  const completed = '■'.repeat(position);
  const remaining = '□'.repeat(array.length - position);

  return bar + `Step ${position}/5: ${completed}${remaining}\n`;
}, 'Progress:\n');


console.log(progressBar);

Practical example: creating a price summary

const pizzaOrders = [
  { name: 'Margherita', price: 10, quantity: 2 },
  { name: 'Pepperoni', price: 12, quantity: 5 },
  { name: 'Supreme', price: 15, quantity: 3 }
];

const orderSummary = pizzaOrders.reduce((summary, order) => {
  const itemTotal = order.price * order.quantity;
  return {
    items: summary.items + order.quantity,
    subtotal: summary.subtotal + itemTotal,
    tax: summary.tax + (itemTotal * 0.2), // 20% tax
    itemsList: [...summary.itemsList, `${order.name} (${order.quantity}x)`]
  };
}, { items: 0, subtotal: 0, tax: 0, itemsList: [] });

const total = orderSummary.subtotal + orderSummary.tax;

console.log({
  ...orderSummary,
  total: Math.round(total * 100) / 100
});
/* Output:
{
  "items": 10,
  "subtotal": 125,
  "tax": 25,
  "itemsList": [
    "Margherita (2x)",
    "Pepperoni (5x)",
    "Supreme (3x)"
  ],
  "total": 150
}
*/

When to use reduce() vs. other methods

Use reduce() when:

  • You require transforms like aggregating, grouping, or counting data.
  • You need to transform an array into a single value.
  • You want to perform calculations on each element and maintain a running total.

Consider using other methods when:

  • You need to process the array elements from right to left, (use reduceRight()).
  • You need to find an element (use find() or findIndex()).
  • You simply want a new array with transformed elements (use map()).
  • You just want to filter elements based on a condition (use filter()).
  • You only need to know if elements meet a condition (use some() or every()).
  • You want to perform an action for each element without accumulating a result (use forEach()).

Conclusion

The reduce() method is a powerful JavaScript array method, providing a way to process arrays and transform the data into any type of value. It's particularly useful for aggregating data and transforming values into a single result. While it has a steeper learning curve than many other array methods, reduce() can be a very useful method to learn.