Rajat Gupta
Rajat's Blog

Rajat's Blog

reduce() method in javascript

Rajat Gupta's photo
Rajat Gupta
·Feb 18, 2022·

9 min read

Subscribe to my newsletter and never miss my upcoming articles

Let's see what MDN has to say: The reduce() method executes a user-supplied “reducer” callback function on each element of the array, in order, passing in the return value from the calculation on the preceding element. The final result of running the reducer across all elements of the array is a single value.

The first time that the callback is run there is no "return value of the previous calculation". If supplied, an initial value may be used in its place. Otherwise, the array element at index 0 is used as the initial value and iteration starts from the next element (index 1 instead of index 0).

pretty intense ☝️.

Actually, this one is quite tricky as compared to map and filter.

for now understand this: Each element of the array passes through the function provided by us in order to give a single value as output.

The best way to understand is through examples. So, let's get the ball rolling:

Example 1: Given an array of numbers, return the sum of all numbers?

const numbersArray = [1, 6, 9, 4];

//we'll understand using normal function:

function sum(accumulator, currentValue){
        return acc+current;
}

const output = numbersArray.reduce(sum);
console.log(output)

Result: 20

So, what the heck just happened. Don't worry, just listen to me carefully and while doing that refer to the above example.

Let's first try to understand this 👇 basic syntax of the reducer function:

reduce((accumulator, currentValue) => accumulator + currentValue)

reducer function is the function that we define inside the reduce method. This is the most important thing to understand. If you get this, the remaining blog will be a cakewalk for you.

accumulator: The value resulting from the call to the reducer function. The very first value of the accumulator is array[0].

currentValue: The current element of the array. The very first value of the currentValue is array[1]. currentValue is always the very next value of the one which the accumulator took in the previous step.

Still not clear. Don't worry just go through the mental model of what happens when we call the sum function in the above example and everything will be crystal clear.

Step 1: Since the very first value of the accumulator is array[0]. Hence. in the above example, it will be 1.
The very first value of the currentValue is array[1]. Hence, in the above example, it will be 6.

Step 2: As per the instructions given in the sum function, accumulator + currentValue that is 1+6 = 7, will be returned (we got the values of both accumulator and currentValue from the above step).

Step 3: The returned value from the above step that is 7 will be stored in the accumulator for the next iteration and the currentValue will now be set to 9.

Step 4: As per the instructions given in the sum function, accumulator + currentValue that is 7+9 = 16, will be returned (we got the values of both accumulator and currentValue from the above step).

Step 5: The returned value from the above step that is 16 will be stored in the accumulator for the next iteration and the currentValue will now be set to 4.

step 6: As per the instructions given in the sum function, accumulator + currentValue that is 16+4 = 20, will be returned (we got the values of both accumulator and currentValue from the above step).

I hope you understood now how the basic version of reduce is working.

Let's do one more similar example:
Example 2: Given an array of numbers return the multiplication of the numbers?

const numbersArray = [1, 6, 9, 4];

//using arrow function:

const output = numbersArray.reduce((acc, current) => acc*current);
console.log(output)

Result: 216

Understand the above example based on the mental model discussed above.

Now, that you have understood the basic version of reduce, let me introduce a little advanced version:
Here's the syntax:

reduce((accumulator, currentValue) => accumulator + currentValue, initialValue)

So, what the heck is initialValue. initialValue is the value to which our accumulator is initialized the first time the reducer function is called value.

Whenever the initialValue is provided the value of other variables changes. Here's what changes when initialValue is present.

accumulator: The very first value of the accumulator is the initialValue, if it is specified.

currentValue: The very first value of the currentValue is array[0] if the initialValue is specified.

Not clear. See the below example.
Example 3:

const numbersArray = [1, 6, 9, 4];

//we'll understand using normal function:

function sum(accumulator, currentValue){
        return acc+current;
}

const output = numbersArray.reduce(sum, 2);
console.log(output)

Result: 22

Here☝️ 2 is the initial value.

Still not clear.
let's again understand via the mental model:

Step 1: Since the very first value of the accumulator is equal to the initialValue. Hence, in the above example, it will be 2.
The very first value of the currentValue this time is array[0]. Hence, in the above example, it will be 1.

Step 2: As per the instructions given in the sum function, accumulator + currentValue that is 2+1 = 3, will be returned (we got the values of both accumulator and currentValue from the above step).

Step 3: The returned value from the above step that is 3 will be stored in the accumulator for the next iteration and the currentValue will now be set to 6.

Step 4: As per the instructions given in the sum function, accumulator + currentValue that is 3+6 = 9, will be returned (we got the values of both accumulator and currentValue from the above step).

Step 5: The returned value from the above step that is 9 will be stored in the accumulator for the next iteration and the currentValue will now be set to 9.

step 6: As per the instructions given in the sum function, accumulator + currentValue that is 9+9 = 18, will be returned (we got the values of both accumulator and currentValue from the above step).

Step 7: The returned value from the above step that is 18 will be stored in the accumulator for the next iteration and the currentValue will now be set to 4.

step 8: As per the instructions given in the sum function, accumulator + currentValue that is 18+4 = 22, will be returned (we got the values of both accumulator and currentValue from the above step).

I hope you understood now how this version too.

MAN WRITING THIS BLOG IS TAKING TOO MUCH TIME. But I have got to complete and you have got to understand. Kill the choices and you'll be free (sounds counterintuitive but it's not).

Let's do some more examples and I'll be using arrow functions only. If you need the same solution to be written in terms of normal functions too, tell me in the comments and I'll be happy to do it.

Example 4: Given an array of numbers, find the sum of all odd numbers.

const numbersArray = [1, 6, 9, 4, 21, 8, 15];
const sumOdd = numbersArray.reduce((acc, current) => current % 2 === 0 ? acc : acc+current, 0)
console.log(sumOdd);

Result: 46

In the above example, for each iteration, the value of the accumulator will remain the same if the number encountered is even. However, Whenever the number encountered is odd, the previous value of the accumulator will be added to the currentValue to give us a new accumulator for the next iteration. The initialValue is 0.

Let's see another example to understand better:

Example 5: Given an array of numbers, filter out the highest value from the array.

const numbersArray = [1, 6, 9, 4, 21, 8, 15];
const max = numbersArray.reduce((acc, current) => acc > current ? acc:current, 0)
console.log(max);

Result: 21

Logic in the above example: If accumulator is bigger than use the same accumulator for the next iteration and if currentValue is bigger, use currentValue as an accumulator for the next iteration.

Here's one more example:
Example 6: Return an object with the sum of odd and even numbers separately?
I want something like this to be returned: {evenSum: 142, oddSum: 71}. Remember, I told you that reduce only returns a single value. Here's a fun fact: that value can be an object.

const numbersArray = [1, 6, 9, 4, 21, 8, 15];

const sumEvenOdd = numbersArray.reduce((acc, current) => current % 2 === 0 ? {...acc,'even':acc['even'] + current} :  {...acc, 'odd':acc['odd'] + current}, {"even":0, "odd":0})}

console.log(sumEvenOdd)

Result: {even: 18, odd: 46}

Some of you might be dumb like me and don't understand things instantly. So here's a little explanation for my kind.👇

Note: in the above example I used the spread operator (...acc), if you don't understand what it is, you may wanna read about it first.

Step 1: The very first value of the accumulator will be set to {"even":0, "odd":0} as this is the initialValue.

Step 2: Now, the first element of the array will be passed through the reducer function. The reducer function will see if the currentValue is divisible by 2. Since the currentValue is 1 (not divisible by 2), the reducer function will return {...acc, 'odd':acc['odd'] + current} which may seem complicated but it's just {"even":0, "odd":0+1} that is {"even":0, "odd":1}.

Step 3: In this iteration, the currentValue is 6 that is even. Hence, the reducer will return {"even":0+6, "odd":1} that is {"even":6, "odd":1}.

Step 4: In this iteration, the currentValue is 9 that is odd. Hence, the reducer will return {"even":6, "odd":9+1} that is {"even":6, "odd":10} .

Step 5: and so on until we get {even: 18, odd: 46}.

Now, one more example, and I promise this will be the last one.
If you have read my blog on filter, I used the same example there and achieved the result using map and filter both. Here we'll achieve the desired outcome using reduce only.

Remember, I told you that reduce only returns a single value and the value can be an object. Here's a fun fact: that value can be an array too.

Example 7: Given the below array:

const details = [{'firstName': 'Rajat', 'lastName': 'Gupta', 'age': 28},
{'firstName': 'Barack', 'lastName': 'Obama', 'age': 50},
{'firstName': 'Elon', 'lastName': 'Musk', 'age': 45},
{'firstName': 'Joe', 'lastName': 'Rogan', 'age': 36},
{'firstName': 'Abdul', 'lastName': 'Kalam', 'age': 64}]

Can you filter out the firstName of the persons having an age of more than 46?

console.log(details.reduce((acc, current) => current.age>46 ?  [...acc, current.firstName] : acc, []))

Result: ['Barack', 'Abdul']

Again for the people who are a little slow like me. Here's a little explanation:

Note: in the above example I used the spread operator (...acc), if you don't understand what it is, you may wanna read about it first.

Step 1: The very first value of the accumulator will be set to an empty array.

Step 2: Now, the first element of the array (that is an object) will be passed through the reducer function. The reducer function will see the age and if since the age is lesser than 46, the value of the accumulator will remain the same for the next iteration (accumulator = []).

Step 3: In this iteration, the age is greater than 46, hence the accumulator's value will change to ['Barack'].

Step 3: The value of the accumulator will remain the same for the next 2 iterations.

Step 4: In this iteration, the age is greater than 46, hence the accumulator will change its value from ['Barack'] to ['Barack', 'Abdul'].

That's all folks.

If you have any doubt ask me in the comments section and I'll try to answer as soon as possible.

I write one article every day related to web development (yes, every single f*cking day). Follow me here if you are learning the same..

If you love the article follow me on Twitter: @therajatg

If you are the Linkedin type, let's connect: linkedin.com/in/therajatg

Have an awesome day ahead 😀!

 
Share this