JavaScript Reducing Arrays. Reduce() Method.

Oleg Ivanov
Geek Culture
Published in
8 min readJul 7, 2021

--

In the day-to-day programming work, we often work with lists (arrays). Sometimes, we want to find elements that meet a certain condition, a Filter() method is a good choice for that, other times we might want to transform elements of the given array based on some logic, then we can apply the Map() method. What about scenarios when we would like to create a single summary value or to reduce a list of elements (array) to a single value?

Photo by Roman Kraft on Unsplash

In this tutorial, we will learn how to use a Reduce() built-in native JavaScript method to aggregate a result or come to one singular value. That value can be a string, a number, a boolean or even an object, etc.

First, let’s try to solve the following problem by applying basic Vanilla JavaScript /a for loop approach.

You are given an array of numbers:

let arrayOfNumbers = [1, 2, 3, 4, 5, 6, 7];

We need to add all the elements of this array together to get the single summary value. Expected result is 1 + 2 + 3 + 4 + 5 + 6 + 7 = 28.

A common approach to solve problems like this is that we first declare a new variable, in our case it is going to be an accumulator, and set its value to 0. Then we iterate over the given array and add current element to that accumulator variable, with every next iteration the value we are storing in that accumulator variable gets increased by the value of the current element. Finally, when the loop has finished, we return an accumulated value.

Below is a pseudocode and code itself for this problem. Try it out! Copy and paste it into your console.

function sum (numbers) {
// declare a new var and set it to 0
let accumulator = 0;
// iterate over an array
for (var i = 0; i < numbers.length; i++) {
// add the current element of the array to that new var till the end // of loop accumulator = accumulator + numbers[i];
}
// return this accumulated value
return accumulator;
}
let arrayOfNumbers = [1, 2, 3, 4, 5, 6, 7];
let result = sum (arrayOfNumbers);
console.log(result);// output -> 28

Here is the output in the console:

This is a very basic way to manually add together all the elements of the array but as you might see, it only works for this very specific situation! For example, if I want to add only first N elements or a length of this array will change, I will have to re-write my code. This is when the Reduce() method comes in very handy!

As always, let’s look at the official definition of this method and syntax at MDN Web Docs:

The Reduce() method executes a reducer function (that you provide) on each element of the array, resulting in a single output value.

The reducer function takes four arguments:

1. Accumulator

2. Current Value

3. Current Index

4. Source Array

// Arrow function
reduce((accumulator, currentValue) => { ... } )
reduce((accumulator, currentValue, index) => { ... } )
reduce((accumulator, currentValue, index, array) => { ... } )
reduce((accumulator, currentValue, index, array) => { ... }, initialValue)
// Callback function
reduce(callbackFn)
reduce(callbackFn, initialValue)
// Inline callback function
reduce(function callbackFn(accumulator, currentValue) { ... })
reduce(function callbackFn(accumulator, currentValue, index) { ... })
reduce(function callbackFn(accumulator, currentValue, index, array){ ... })
reduce(function callbackFn(accumulator, currentValue, index, array) { ... }, initialValue)

All right, armed with this theoretical knowledge of what the Reduce() method does, let’s solve the problem above by using this method.

let arrayOfNumbers = [1, 2, 3, 4, 5, 6, 7];let reducerFunction = (accumulator, currentValue) => accumulator + currentValue;let result = arrayOfNumbers.reduce(reducerFunction)
console.log(result); // output -> 28;

This code above might look a little bit awkward, so let’s make it shorter and use an arrow function expression as the official documentation recommends:

let arrayOfNumbers = [1, 2, 3, 4, 5, 6, 7];let sum = arrayOfNumbers.reduce ((accumulator, currentValue) => accumulator + currentValue, 0);console.log(sum); // output -> 28;

or using an inline callback function:

let arrayOfNumbers = [1, 2, 3, 4, 5, 6, 7];let sum = arrayOfNumbers.reduce (function (accumulator, currentValue) {return accumulator + currentValue}, 0);console.log(sum);// output -> 28;

No matter what syntax you select, the output will be the same for all styles noted above.

What is happening here? We are invoking the Reduce() method on our source or an input array arrayOfNumbers and passing it two arguments: a callback function defined as an arrow function expression in this case (accumulator, currentValue) => accumulator + currentValue and an optional initial value or the accumulator set to 0 in this case. Then, the method executes the callback function for each element of the source array in turn (1, 2, 3, 4 … 7), passing in the current value of the accumulator and the current element each time. After each iteration, the callback function updates the value of the accumulator similar to what we saw before in this line of code accumulator = accumulator + numbers[i] and this updated value of the accumulator is then passed as the first argument to the callback function and so on till the end of the source array. When there is nothing left to go over in the input array, the final value of the accumulator is returned same as return accumulator in the example I posted in the beginning.

The initialization start value is optional as it is stated in the documentation, but leaving it out might lead to something you do not really expect! If there is no the initial start value, then the first element in the array is used as the starting value / initial accumulator value. Check out the following two examples:

We have already learnt how to apply and use the Reduce() method on primitive types, now let’s dive into and demonstrate using this method on objects.

Assume that we have a team of superheroes (represented in an array of objects), and we need to determine which hero, for example, is the fastest one. For all fans of superheroes, I would like to assure you that data below is valid and coming from this website! Let’s figure out who is the fastest one — “Iron man”, “Black Widow” or “Hulk” 🍾 🙌 🎉!!!

let listOfHeroes = [
{
"Name":"Anthony Edward 'Tony' Stark",
"CurrentAlias":"Iron Man",
"Intelligence":6,
"Strength":6,
"Speed":5,
"Durability":6,
"EnergyProjection":6,
"FightSkills":4
},
{
"Name":"Natalia Alianovna 'Natasha' Romanova",
"CurrentAlias":"Black Widow",
"Intelligence":3,
"Strength":3,
"Speed":2,
"Durability":3,
"EnergyProjection":3,
"FightSkills":6
},
{
"Name":"Dr. Robert Bruce Banner",
"CurrentAlias":"Hulk",
"Intelligence":6,
"Strength":7,
"Speed":3,
"Durability":7,
"EnergyProjection":5,
"FightSkills":4
}]

A common approach to determine the largest value in any array would be to assume that one value, for example, the first one in the given array is the largest one, then iterate over the array starting from the second element and compare each element with the default largest value. If the current value is more that the default largest value, then do reassignment. Once we know what the largest value is, we can run the second for loop over the initial array to determine which index (or our hero as an object) matches this largest value and return then the hero object. Let’s solve this problem by using Vanilla JavaScript and the for loop. Below is the code and output:

function fastestHeroe(array) {
// assume the first element in this array is the largest one
let speedFast = array[0].Speed;
// iterate over the array starting from the second element and till the end of this array
for (var i = 1; i < array.length; i++) {
// if the current element is more than the assumed largest/first then assign this current element to speedFast var
if (array[i].Speed > speedFast) {
speedFast = array[i].Speed;
}}
// iterate over the array
for (var j = 0; j < array.length; j++) {
// if a value of “Speed” key is equal to the found largest one then return the current objif (array[j].Speed === speedFast) {
return array[j];
}}}

If you run this code, it should return “Tony” Stark because his “Speed” value is 5 and that is more than “Black Widow” and “Hulk” each has.

Now, let’s demonstrate how same problem can be solved with the Reduce() method:

var fastest = listOfHeroes.reduce(function (accumulator, hero) {return (accumulator.Speed || 0) > hero.Speed ? accumulator : hero;}, {});

The Reduce() method’s output is the same as we got after implementing the for loop approach.

Great! It took us just a few lines of code to reduce the initial array of the objects to determine which hero is the fastest one compared to multiples lines of code and two loops in the Vanilla JavaScript / the for loop approach.

As for the winner in this the Reduce() method vs the for loop competition, “Tony” Stark is the fastest Superhero, because his speed is 5 and it is greater than anyone else has in this grid of superpowers. Congrats “Tony”! 💯

Photo by Marjan Blan | @marjanblan on Unsplash

To summarize, the Reduce() method is used when we want to get some information from each element in the input array and gather that information into the final signal summary value (accumulator). We need to consider three main aspects here: the source array or the array we want to reduce; the callback function or reducer, the one that defines what sort of manipulation needs to be done; the initial start value for our accumulator variable. The Reduce() function iterates over the source array, calling the reducer callback function each time, which in return returns the updated value of the accumulator.

We still can, of course, accomplish the same using the for loop as demonstrated above, but using the native built-in Reduce() function frees us from having to code the looping mechanisms, write multiple lines of repetitive code, declare and accumulate variables in accumulator type of variable, and then return this accumulator at the end.

If you find this information useful, please feel free to follow me. Hope you enjoyed this short guidance on Reduce() method in JavaScript, be strong and stay tuned!

--

--