The JavaScript reduce method is one of the methods used in functional programming and can be quite hard to understand. In this article, we will explore how it works and take a look at some examples.
The Reduce Method: What is it?
The reduce method executes a callback function on every element of an array, from left to right, and returns a single output value. The syntax is as follows:
array.reduce(callback(accumulator, currentValue, currentIndex, arr), initialValue);
or rather,
array.reduce(callback, initialValue);
Remember, the callback is the function that will be called upon every single element of an array, and it takes in four arguments as shown above and described below.
The accumulator accumulates the returned value of the callback function. It is a required parameter.
The currentValue is the value of the current element being processed in the array. It is a required parameter.
The currentIndex is the array index of the current element being processed in the array. It is an optional parameter.
The arr is the array object the current element belongs to. It is an optional parameter.
The initialValue is the value of the first argument to the first call of the callback function. If no initialValue is provided, the first element in the array will be used as the initial accumulator value. Therefore, the initial callback function will start at index 1, not index 0 of the array. It is thus safer to provide an initialValue, and should be one of the first things to check out for when debugging.
Don't worry if the syntax seems a little confusing. We will dive deeper into the workings of the reduce method using a couple of examples.
Let's take a look at some examples now, shall we?
1. Sum of array elements
Let's take a look at a classic example of how one can sum up elements of an array using the for loop:
let results = 0;
const arrayNumbers = [10,20,30];
for(let num=0; num<arrayNumbers.length; num++){
results += arrayNumbers[num];
}
console.log(results); //results = 60
This can also be done using the reduce
method without mutating the results
variable as shown below:
//initial value or starting point of the callback function
const initialValue = 0;
//array of numbers
const arrayNumbers = [10,20,30];
//the reduce method takes in the sum function as the callback function and the initialValue
const results = arrayNumbers.reduce(sum, initialValue);
//the sum function
function sum(accumulator, currentValue){
return accumulator + currentValue;
}
console.log(results); //results = 60
The explanation for the above code is as follows:
The first time the callback function is called, the
accumulator
will be equal to theinitialValue
which is 0.On each call to the function, the
currentValue
is added to theaccumulator
, for example 10 is added to the accumulator, thus accumulator equals 10, and the calculation is repeated for each element on the array, with thecurrentValue
changing to the next number in the array.When there are no more numbers left in the array, the method returns the
accumulator
value of the last callback invocation, which is 60.
This can also be written using an arrow function as shown below:
const arrayNumbers = [10,20,30];
const results = arrayNumbers.reduce((accumulator, currentValue) => {
return accumulator + currentValue;
}, 0);
console.log(results) //results = 60
Pretty cool, right? Let's check out other ways to use the reduce
method.
2. Find the maximum element in a numeric array
The reduce
method here works by comparing each value to find the maximum element of an array. This method has its pros over using apply
and the spread(...)
operator, which may fail or return a wrong result if the array has too many elements.
const arr = [1,5,25,13,55];
const largestNum = arr.reduce((accumulator,value) => {
if(accumulator> value){
return accumulator;
} else {
return value;
}
}, []);
console.log(largestNum); //returns 55
The Math.max()
function can also be used in place of an if
statement to return the largest number.
const arr = [1,5,25,13,55];
const largestNum = arr.reduce((accumulator,value) => {
return Math.max(accumulator,value);
}, []);
console.log(largestNum); //returns 55
3. Sum values in an object array
The reduce
method can be used to sum up values contained in an array of objects. However, an initialValue
must be provided to avoid running into an error.
Let's say we have an object property of shoppingList
, and we need to get the total cost of the products.
const shoppingList = [
{
product: 'eggs',
price: 10,
numberOfItems: 30
},
{
product: 'bananas',
price: 5,
numberOfItems: 10
},
{
product: 'cups',
price: 20,
numberOfItems: 15
}
];
Using the reduce method, we can get the total or accumulated value of the products, whose price
and numberOfItems
values can be accessed using the dot notation.
const totalCost = shoppingList.reduce((accumulator, item) => {
return accumulator + (item.price * item.numberOfItems);
}, 0);
console.log(totalCost); //returns 650
4. Flatten an array
The reduce method can also be used to flatten a nested array in place of the .flat
method.
const data = [[15,25], [30,50], 3];
In the example below, we set the initial value to an empty array and concatenate the val
to the acc
.
const flat = data.reduce((acc, val) => {
return acc.concat(val);
}, []);
console.log(flat); //return [15, 25, 30, 50, 3]
Let's go through another example, where arrays can be nested in more complicated ways such as shown below:
const flowers = [
{
name: 'rose',
color: ['red', 'yellow', 'white', 'pink', 'orange']
},
{
name: 'dahlia',
color: ['orange', 'pink', 'white', 'lavender', 'red']
},
{
name: 'morning glory',
color: ['purple', 'blue', 'red', 'white', 'pink']
}
];
We can access the colors from each object using the dot notation on the cur
argument. We can then use the forEach()
method to push every value that lies in the color property to acc
.
const allColors = flowers.reduce((acc,cur) => {
cur.color.forEach(col => acc.push(col) )
return acc;
}, []);
This results in a single array that contains all the color
values. However, this array has multiple repeat elements, which we can fix using an if
statement and indexOf()
, which will check if an element exists in acc
or not and will update accordingly.
const allColors = flowers.reduce((acc,cur) => {
cur.color.forEach(col => {
if(acc.indexOf(col) === -1){
acc.push(col);
}
})
return acc;
}, []);
Which thus leads to a single array that has only one occurrence of an element.
["red", "yellow", "white", "pink", "orange", "lavender", "purple", "blue"]
5. Counting instances of an object
The reduce method can also be used to sum up the instances of values in an object.
Let's say we have an array such as this:
const colors = ['green', 'blue', 'purple', 'red', 'blue', 'purple', 'purple'];
To find the instances of a value appearing in the array, we can use an if
statement to count the number of times a color appears in acc
. If a color appears more than once, we add up the number of times and return the total number of times the color appears, else we return 1 for the colors that only appear once.
const countColors = colors.reduce((acc, color) => {
if(color in acc){
acc[color]++
} else {
acc[color] = 1;
}
return acc;
}, []);
The result will thus be:
[green: 1, blue: 2, purple: 3, red: 1]
Conclusion
The reduce
method can seem to be more complex compared to other JavaScript methods. Having a clear understanding of the syntax, the core concepts as well as some of the cases in which the method is used can be of much help and can be a powerful tool in data manipulation.