loading...

Javascript reduce 101

iggredible profile image Igor Irianto Updated on ・4 min read

Javascript reduce() function is a useful array method. Unfortunately I never spent much time learning about it because it looks too complex. The truth is, it is not at all that hard! We just need to break it down into enough small chunks. So what are we waiting for? Let's try to understand it!

What does it do?

Per Mozilla:

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

I think the description is slightly misleading, because when I hear a "single value" - I think of a simple number/ string output, but reduce can easily return an object or another array.

Examples

There are infinite examples reduce can be used. We will cover the basic 3:

  1. Reducing to a single number
  2. Reducing to an array
  3. Reducing to an object.

Reducing to a single number

The most common use of reduce is to sum up all elements in an array.

const arr = [1,2,3,4];
arr.reduce((acc, currentVal) => acc + currentVal);
// returns 10

Ok, what just happened?

Reduce iterates through each element in an array (except if we don't give starting value, it uses the first element as the starting value). In each iteration, there is always an accumulator and current value. As you are reading through examples. Try to think during each iteration, who is the accumulator and who is the currentValue?

  • In the first iteration, acc is 1 and currentVal is 2. It performs acc + currentVal; 1 + 2.
  • In second iteration, acc is now 3 and currentVal is 3. It performs acc + currentVal; 3 + 3.
  • In the third iteration, acc is now 6 and currentVal is 4. It performs acc + currentVal; 6 + 4.
  • The iteration stops because we reached the end of the array. Acc is 10. It returns the final value of acc, 10.

Reducing to an array

Let's say we are given an array

const wealthiestPeople = [
    {name: "Gates", worth: 105700000000},
    {name: "Bezos", worth: 131000000000},
    {name: "Buffet", worth: 82500000000},
    {name: "Arnault", worth: 76000000000},
    {name: "Helu", worth: 75600000000}
]

Boy, what would you do with that money 🤑? Anyway, we want to map and filter all the worth of those whose net worth is less than 100 billion and return the same array.

wealthiestPeople.reduce((acc, currentVal) => {
  if(currentVal.worth > 100000000000){
    return acc
  }
  acc.push(currentVal)
  return acc
 }, [])

// returns [ { name: 'Buffet', worth: 82500000000 },
  { name: 'Arnault', worth: 76000000000 },
  { name: 'Helu', worth: 75600000000 } ]

Isn't that cool that reduce can map and filter at the same time? Let's break it down.

  • If you notice, we passed an initial value [] after we use reduce function. As always, we are iterating through each element.

  • In the first iteration, our acc is [], currentVal is {name: "Gates", worth: 105700000000}. It fails the worth test, so it returns acc, which is [].

  • In the second iteration, our acc is []. currentVal is {name: "Bezos", worth: 131000000000}. It also fails the worth test. It returns acc, which is [].

  • In the third iteration, our acc is []. currentVal is {name: "Buffet", worth: 82500000000}. It passes the worth test. It pushes Buffet object into acc. It returns acc, which is [{name: "Buffet", worth: 82500000000}].

  • In the fourth iteration, our acc is [{name: "Buffet", worth: 82500000000}]. currentVal is arnault object. It passes the worth test. It pushes {name: "Arnault", worth: 76000000000} into acc. It returns acc, which is [{name: "Buffet", worth: 82500000000}, {name: "Arnault", worth: 76000000000}].

  • In the fifth iteration, our acc is [{name: "Buffet", worth: 82500000000}, {name: "Arnault", worth: 76000000000}]. currentVal is Helu object. It passes the worth test. It pushes Helu object. It returns acc, which is [ { name: 'Buffet', worth: 82500000000 },{ name: 'Arnault', worth: 76000000000 },{ name: 'Helu', worth: 75600000000 } ].

I hope you are starting to see a pattern emerging from this!

A super awesome reader mentioned that this can be easily done using filter:

wealthiestPeople.filter(function(p) {
  return p.worth < 1100000000000
})

In this case, .filter() is a better tool for the job.
A better example where reduce is useful is when we have to use both map and filter. For example, if we have to not only filter based on worth, but turn the amount into string and add $ value, something like:

// same reduce cod as above, except
// add this line before push
currentVal.worth = `$${currentVal.worth}.00`
acc.push(currentVal)
// returns
[ { name: 'Buffet', worth: '$82500000000.00' },
  { name: 'Arnault', worth: '$76000000000.00' },
  { name: 'Helu', worth: '$75600000000.00' } ]

Another super awesome reader mentioned that reduce is useful than map + filter combo because we only have to iterate array once instead of twice: once during map and once during filter. Anytime we perform map + filter, think of how you can use reduce instead!

Back to the example - if instead you wanted to add all their wealth together:

wealthiestPeople.reduce((acc, currentVal) => {
  return acc + currentVal.worth;
}, 0)

Reducing to an object

Our last task is to reduce to an object. Given the same array, can we reduce it to an object with their name as the key, and {worth: xxx} as their value? Something like:

{
  'Buffet': {worth: xxx},
  'Gates': {worth: xxx},
  // etc
}

Before read on, why don't you try 5-10 minutes - struggle for a bit - and try to figure it out yourself! If you're stuck, don't worry (I got stuck when learning it first time too) read along! The struggling it the key, so at least give it a try.

.
.
.

wealthiestPeople.reduce((acc, currentVal) => {
  acc[currentVal.name] = {worth: currentVal.worth}
  return acc
}, {})

When to know to use reduce?

Anytime we are given an array as input is a good chance to use reduce. Whenever an array operation is done and we need to return another array, an object, or a single value, reduce can probably do it for you.

Are there any other times you all find it useful to use reduce method? Share below!

Let me know if you have any questions/ concerns. Thank you for reading this far. Happy codin'!

Posted on by:

iggredible profile

Igor Irianto

@iggredible

Husband 👫. Programmer 💻. Vim 🤓. Web Development should be explained as simple as possible, but no simpler 💡

Discussion

markdown guide
 

It doesn't make any sense to use reduce to reduce it to an array. We could use filter only to do the same:

wealthiestPeople.filter(function(p){
  return p.worth < 100000000000
})
 

Yup! Totally makes sense. I agree that using reduce here is overkill.

However, my goal is to show two things:

  1. How to understand how accumulator and current value change each iteration
  2. That reduce can return either: an array, an object, or a primitive value.

I can probably think of another case where reduce is more useful than map/filter, but I'll have to change the example. I think it's easier to grasp of I use one array example throughout the whole article. It was a huge revelation when I first learned that reduce can return array or object and I hope to convey the same to readers :)

Really appreciate the feedback!

For those who read this, filter is the better tool for this situation. But the point stands that reduce can give the same result, just more work is required.

 

A good example would be a reduce which does both a map and a filter - if you did the same with map, then filter, you'd have to iterate over the array twice.

I updated the post to include a basic map/ filter case. Thank you so much for the suggestion!

I hope it conveys the point :)

 

I get what you mean! I think it’s important to make it clear that’s not the best solution since in this case reduce will be more memory consuming. Keep the good work!

I updated the post so it now includes your filter example 👍

 

Never thought about reducing to an obj and also rearranging the key, fricking awesome! Thanks