JavaScript Reduce Function: A Comprehensive Guide with Examples

Learn everything you need to know about JavaScript's reduce() function with this comprehensive guide. This article covers the basics of reduce(), as well as advanced techniques and real-world examples. Whether you're a beginner or a seasoned pro, you'll learn how to use reduce() to write more efficient and elegant JavaScript code.

As the year begins, I have decided to make a series of articles that explain the various APIs (Application Programming Interfaces) in the Javascript language, wherein each article we breakdown a commonly used function in Javascript and try to go through its various applications.

The first function we will be going through is the ‘Reduce’ higher-order function, mainly because out of all the JS array methods, it took me a bit of time to understand how the Reduce function works.

This article assumes that the reader understands other array methods like Map and Filter because it will help in understanding how Reduce works. In order to fully grasp the idea behind Reduce, we will look at a few examples of simple solutions using for loops and then implement those same solutions using the Reduce function, then we will look at some more advanced use cases for the Reduce function.

Example 1

The first example we will look at is a common one, calculating the sum of items in an array. This requires a simple solution and using a for loop the solution should look like this:

const arrayItems = [1,2,3,4,5,6];
let sum = 0;

for (let i = 0; i < arrayItems.length; i++) {
	sum = sum + arrayItems[i];
}
// sum = 21

The solution above is pretty straightforward, where we add each item in the array and store the result in the sum variable. So the next step is to implement this same solution using Reduce which should look like the code below:

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

const sum = arrayItems.reduce(function(accumulator, currentItemInArray){
	accumulator = accumulator + currentItemInArray;
    return accumulator;
}, 0);

// sum = 21

Looking at the two examples above it’s pretty obvious that the for loop example seems simpler and this has been the cause of some arguments in the ecosystem, but this example is an overkill and we are only using it make it easy to understand how the Reduce function works, so let’s work through the example.

We need to, first of all, understand what the Reduce function is. It is a method that exists on every Javascript Array and it enables us to loop through each item in the array and perform a function on each of those items, this is pretty similar to the behavior of the Map function but it has a twist, it allows us to return any value from our function in a particular iteration which will exist as a parameter (argument) in that function in the next iteration (that value is commonly known as the accumulator).

To explain further, the Reduce function takes 2 arguments:

  • Callback function: This is a function that contains 4 parameters typically, but right now we are only concerned with the first accumulator and the second being the current item in the array during that iteration.
  • Initial value: This is the initial value of the accumulator when the iteration starts, in the example above the value is 0, which means the initial value of the accumulator will be 0.

Back to our example:

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

const sum = arrayItems.reduce(function(accumulator, currentItemInArray){
	accumulator = accumulator + currentItemInArray;
    return accumulator;
}, 0);

// sum = 21

It can be further broken out into the callback function and the initial value:

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

function callbackFunction(accumulator, currentItemInArray){
    accumulator = accumulator + currentItemInArray;
    return accumulator;
}

const initialValue = 0;

const sum = arrayItems.reduce(callbackFunction, initialValue);

// sum = 21

Now the tricky part for me was how the accumulator works, and to explain it we will go through each iteration in the loop.

Iteration 1

In the first iteration, since our initial value is 0, our accumulator will have a value of 0 so our function will look like this:

const arrayItems = [1,2,3,4,5,6];
// 1 is the current item in the array

function callbackFunction(accumulator = 0, currentItemInArray = 1){
    accumulator = 0 + 1;
    return accumulator // which is 1;
}

callbackFunction will return a value of 1, this will be automatically be used as the next value for the accumulator in the second iteration.

Iteration 2

const arrayItems = [1,2,3,4,5,6];
// 2 is the current item in the array

function callbackFunction(accumulator = 1, currentItemInArray = 2){
    accumulator = 1 + 2;
    return accumulator // which is 3;
}

In this iteration, our accumulator will have a value of 1 which was returned in our iteration 1 and the callbackFunction will return a value of 3 in this iteration which means that our accumulator will have a value of 3 in our third iteration.

Iteration 3

const arrayItems = [1,2,3,4,5,6];
// 3 is the current item in the array

function callbackFunction(accumulator = 3, currentItemInArray = 3){
    accumulator = 3 + 3;
    return accumulator // which is 6;
}

In the third iteration, our accumulator will have a value of 3 which was returned by the callbackFunction in iteration 2 and callbackFunction will return a value of 6 which is to be used as the value of accumulator in iteration 4. These steps will repeat themselves until we get to the last item in the array which is 6.

The example above as I mentioned before can be an overkill, so let’s look at a problem that we can implement a solution using Reduce function (this doesn’t mean that a for loop cannot be used to implement a working solution).

Example 2

The second example will involve counting the number of occurrences of each element in an array, for example:

//Given an input
const fruits = ['apples', 'apples', 'bananas', 'oranges', 'apples', 'oranges', 'bananas', 'grapes'];

// should give an output of
const count = { 'apples': 3,'oranges': 2,'bananas': 2, 'grapes': 1 };

Let’s implement the solution then go through each iteration and see what is happening:

const fruits = ['apples', 'apples', 'bananas', 'oranges', 'apples', 'oranges', 'bananas', 'grapes'];

function countOccurrence(accumulator, currentFruit){
	const currentFruitCount = accumulator[currentFruit];
    // if the fruit exists as a key in the  object, increment its value, else add the fruit as a key to the object with a value of 1

    if(currentFruitCount) {
    	accumulator[currentFruit] = currentFruitCount + 1;
    } else {
    	accumulator[currentFruit] = 1
    }

    return accumulator;
}

const initialValue = {};

const count = fruits.reduce(countOccurrence, initialValue);

The solution is written to be as verbose a possible so we can understand what is going on in the code. As we did before let’s go through the first few iterations.

Iteration 1

In the first iteration, since we made our initial value an empty object, the value of accumulator will be an empty object, which means that the countOcurrence function will look this the below code when it is called:

const fruits = ['apples', 'apples', 'bananas', 'oranges', 'apples', 'oranges', 'bananas', 'grapes'];

// current element is 'apples'

function countOccurrence(accumulator = {}, currentFruit = 'apples'){
    // since currentFruit = 'apples' then accumulator[currentFruit] = accumulator['apples']

	const currentFruitCount = accumulator[currentFruit];
    // currentFruitCount will be null since accumulator is an empty object

    if(currentFruitCount) {
    	accumulator[currentFruit] = currentFruitCount + 1;
    } else {
        // this block will run since accumulator is empty
        // currentFruit = 'apples'
    	accumulator['apples'] = 1
        // accumulator should look like this: { 'apples': 1 }
    }

    return accumulator // which is { 'apples': 1 };
}

Since accumulator is an empty object, currentFruitCount will be null which means the else block will run where a new key (apples) with the value of 1 will be added to the accumulator and returned from the function which will be passed as the value of the accumulator in the second iteration.

Iteration 2

In the second iteration, our accumulator will have the value of { 'apples': 1 } which was returned by the countOccurrence function in the first iteration and the countOccurrence function will look like the code below:

const fruits = ['apples', 'apples', 'bananas', 'oranges', 'apples', 'oranges', 'bananas', 'grapes'];

// current element is 'apples'

function countOccurrence(accumulator = { 'apples': 1 }, currentFruit = 'apples'){
    // since currentFruit = 'apples' then accumulator[currentFruit] = accumulator['apples']

	const currentFruitCount = accumulator[currentFruit];
    // currentFruitCount will be 1 

    if(currentFruitCount) {
        // this block will run since currentFruitCount is 1
        // currentFruit = 'apples'
    	accumulator['apples'] = 1 + 1;
        // accumulator should look like this: { 'apples': 2 }
    } else {
    	accumulator[currentFruit] = 1
    }

    return accumulator // which is { 'apples': 2 };
}

Since the accumulator contains a key (‘apple’) with the value of 1, currentFruit will be 1 which means the if block will be run, in that block the value of the apple key will be incremented by 1 making it 2, this new value will be updated in the accumulator object to make it { 'apples' : 2 } , this value will be returned by the countOccurrence function and passed as the value for the accumulator in the third iteration.

Iteration 3

For our third iteration, accumulator has the value of { apples: 2 } which was returned by countOccurence during the second iteration, the countOccurence function will look like the code below:

const fruits = ['apples', 'apples', 'bananas', 'oranges', 'apples', 'oranges', 'bananas', 'grapes'];

// current element is 'bananas'

function countOccurrence(accumulator = { 'apples': 2 }, currentFruit = 'bananas'){
    // since currentFruit = 'bananas' then accumulator[currentFruit] = accumulator['bananas']

	const currentFruitCount = accumulator[currentFruit];
        // currentFruitCount will be null since accumulator doesn't contain 'bananas'

    if(currentFruitCount) {
        accumulator[currentFruit] = currentFruitCount + 1;
    } else {
        // this block will run since currentFruitCount is null
        // currentFruit = 'bananas'
    	accumulator['bananas'] = 1
    }

    return accumulator // which is { 'apples': 2, 'bananas': 1  };
}

This iteration is similar to the first one, since bananas doesn’t exist in accumulator it will be added to the object and given a value of 1 , making accumulator look like this: { 'apples': 2, 'bananas': 1 } and this will become the value of accumulator for the fourth iteration.

The process will repeat itself until the Reduce function has iterated through each element in the array.

Wrapping up

I really hope these examples were clear enough to create a mental model of how the Reduce function works. Thanks!!!

#javascript #funtion #web-development

JavaScript Reduce Function: A Comprehensive Guide with Examples
1 Likes22.45 GEEK