Javascript Reduce 101

October 31, 2019

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'!

© Copyright 2021 Igor Irianto