Introduction
[The .reduce()
array method works a bit differently than other array methods. It is a bit more complex than the other methods, however, with some imagination, it allows one to perform very complex operations with very little code.
Usually, the array methods return a new array. However, in the reduce
array method, only a single variable is returned. This single variable is passed into each loop and is accessed as the first parameter of the callback. You can then modify this single variable each loop which must also be returned each loop. This single variable then becomes the final result returned by the reduce
array method once it has finished looping over all of the elements. This single variable can be considered an “accumulator” or “total” as you typically add to it on each loop.
In short, the reduce
array method has a variable that allows us to modify each loop. You are reducing your values from the original array down to a single value, hence the name reduce
.
Let’s have a look at a basic example before diving in a bit deeper:
// Numbers that we will loop through
const values = [2, 3, 5, 10, 20];
const sum = values.reduce((total, value) => {
// Add our current element from the array to our 'total' accumulator
total += value;
// We have to return our 'total' accumulator
return total;
// You can see we are setting an initial value of 0 after the callback function
}, 0);
console.log(sum);
// Returns:
// 40
Syntax
NOTE: The reduce
array method does not modify the original array. It returns a single value, however, this value can be an array or an object.
The Callback Function
This is the function that runs each time the array method loops, and gives you access to the following arguments:
-
previousValue: This is the value that is passed from the previous loop, allowing you to build onto it each iteration of the loop
-
currentElement: This is the current element from the array that you are working with
-
index: (Optional) The current index of where we are in the array
-
array: (Optional) The original array
reduce
was called on
initialValue (optional)
This is the initial value for the previousValue
variable. If we don’t specify an initial value then the reduce
method will start with the first value in the array as previousValue
and the second value in the array as currentElement
.
const values = [100, 200, 300, 400, 500];
const endResult = values.reduce(
(previousValue, currentElement, index, array) => {
return previousValue;
},
);
A note regarding the initial value
More often than not, you’ll need to set the initial value for your reduce
array methods. If you do not provide a value, it will set the previousValue
as the element at index 0 of the array, and then the currentElement
as index 1 of the array. Basically, it’s starting one step forward. This works fine if your previousValue
is the same data type as the currentElement
and you would expect the end result of the array method to have the same data type.
Let’s look at a case where a problem arises if we don’t specify an initial value.
We have a bunch of values (nestedValue
) that are nested inside of objects. We want to add these together:
// Adding these values together should give us a result of 40
const values = [
{ nestedValue: 10 },
{ nestedValue: 10 },
{ nestedValue: 10 },
{ nestedValue: 10 },
];
const sumOfValues = values.reduce((total, currentObject) => {
// Add the 'nestedValue' property from the current object in the array
total += currentObject.nestedValue;
return total;
});
// We do not get our expected answer of 40
console.log(sumOfValues);
// returns:
// [object Object]101010
We did not get our expected result of 40
and instead had [object Object]101010
returned. This is because we didn’t specify an initial value. JavaScript used our first value in the array { nestedValue: 10}
as previousValue
. Then when it came to adding currentObject.nestedValue
from the current element to previousValue
, it was trying to perform the following equation: { nestedValue: 10 } += 10
. If we used an initialValue
of 0
, this issue would not have occurred.
This issue arose because our previousValue
was being set to the first element in the array, which was an object when we needed the previousValue
to be of a number type as we are adding numbers to it.
Practical examples
Let’s have a look at some practical examples.
Practical example 1: Add all of the numbers
In this example, we have an array of integers. We add all of the numbers so that we get a total sum of all of the values.
// Sum of these values is 25 (5 + 5 + 5 + 10)
const values = [5, 5, 5, 10];
const sumOfValues = values.reduce((total, value) => {
// Add the current value to our total
total += value;
// Return the total
return total;
});
console.log(sumOfValues);
// Returns:
// 25
Refactored to be more concise:
// Sum of these values is 25 (5 + 5 + 5 + 10)
const values = [5, 5, 5, 10];
const sumOfValues = values.reduce((total, value) => (total += value));
console.log(sumOfValues);
// Returns:
// 25
Practical example 2: Get the total cost of all products
In this example, we have a list of product objects, each containing a title and a price. We add all of the product prices so that we can get a total for all of our products.
const products = [
{ title: 'Cheese', price: 15.0 },
{ title: 'Milk', price: 8.99 },
{ title: 'Bread', price: 22.0 },
{ title: 'Egg', price: 5 },
];
const totalCost = products.reduce((total, currentProduct) => {
total += currentProduct.price;
return total;
// Setting the initial 'total' to 0
}, 0);
console.log(totalCost);
// Returns:
// 50.99
Refactored to be more concise:
const products = [
{ title: 'Cheese', price: 15.0 },
{ title: 'Milk', price: 8.99 },
{ title: 'Bread', price: 22.0 },
{ title: 'Egg', price: 5 },
];
const totalCost = products.reduce(
(total, currentProduct) => (total += currentProduct.price),
0,
);
console.log(totalCost);
// Returns:
// 50.99
Practical example 3: Get the total cost of in-stock products
In this example, we add the prices of a list of products like the previous example. However, this time we need to check that the product is in stock. We also have a quantity for each product being purchased, so we need to calculate this as well.
// All of the in-stock products added together equals 170.95
const products = [
{ title: 'Cheese', inStock: false, quantity: 2, price: 15.0 },
{ title: 'Milk', inStock: true, quantity: 5, price: 8.99 },
{ title: 'Bread', inStock: true, quantity: 3, price: 22.0 },
{ title: 'Egg', inStock: true, quantity: 12, price: 5 },
];
const totalCost = products.reduce((total, currentProduct) => {
if (currentProduct.inStock === true) {
total += currentProduct.price * currentProduct.quantity;
}
return total;
}, 0);
console.log(totalCost);
// Returns:
// 170.95
Refactored
You could refactor the function so that all of the logic is handled with a ternary in the return. However, one could strongly argue that turning this function into a one-liner makes it difficult to read and understand. In this case, the original logic might have been a better way forward.
// All of the in-stock products added together equals 170.95
const products = [
{ title: 'Cheese', inStock: false, quantity: 2, price: 15.0 },
{ title: 'Milk', inStock: true, quantity: 5, price: 8.99 },
{ title: 'Bread', inStock: true, quantity: 3, price: 22.0 },
{ title: 'Egg', inStock: true, quantity: 12, price: 5 },
];
const totalCost = products.reduce(
(total, currentProduct) =>
inStock ? (total += currentProduct.price * currentProduct.quantity) : total,
0,
);
console.log(totalCost);
// Returns:
// 170.95
Video on array .reduce() method
Lesson task
Knowing how to use reduce
is important. You can reduce data down to single objects with some imagination, making it very powerful.
Goal
You will practise using the reduce
array method.
Brief
Complete the Level 1 process.
NOTE: Lesson tasks do not get submitted on Moodle and are not assessed by tutors. They are mainly there for you to practise what you have learned in the lesson.
Level 1 process
- Fork the Array Method Exercises repo and complete the exercises in the
reduce
directory.
NOTE: You will only need to fork this repo once. You will reuse it for all of your array method exercises.