Javascript .reduce Explained

M.
M.
Sep 5, 2018 · 6 min read

The .reduce function is a part of the Javascript’s array iterator methods library. When I was first applying to engineer programs I was ALWAYS asked about my knowledge of these functions. They make engineers' lives easier by allowing them to manipulate data structures (primarily arrays) with just a few lines of code. However, not all of these functions are created equal; .reduce, in particular, has been known to haunt the dreams of novice developers. My aim in this article is to demystify this incredibly useful function so that any aspiring devs out there can spend less time banging their heads against walls and more time building super cool applications.

What does .reduce do?

.reduce takes a collection, a callback, and a (optional) starting value and manipulates the starting value using the elements within the collection. Confused? Let’s see this concept in a real world non-technical example:

Say you are a farmer and you have a basket full of different kinds of apples. You have 3 red apples, 5 green apples, and 2 yellow apples. You want to know how many apples total you have. So you start at zero. Then, you see your 3 red apples. You add 3 to your initial amount of 0. You have 3 now. Next, you see your 5 green apples. You add 5 to your current amount of 3. You have 8 now. Finally, you take your remaining 2 yellow apples and add that to your current amount of 8. You have 10 total apples. You just REDUCED your collection of various apples into one amount. Let’s see what that would look like in code:

let apples = [3, 5, 2]let totalApples = apples.reduce((accumulate, current) => {
accumulate = accumulate + current

return accumulate
}, 0)//totalApples now equals 10

Now, if you’re familiar with other iterator methods like .map or .forEach or even if you’re familiar with for or while loops you might be asking, “Why would we use a complicated function like .reduce to perform the same task that one of these other functions could perform?” And you’d be right. In this case, you could use one of those other methods and the result would be the same. However, before we can see .reduce really shine we need to understand its syntax, which is why I chose a very simple example. Let’s breakdown the above code before we move on. Please bear with me here; It is important we understand the core elements of .reduce before we are able to use its full potential.

The first line of code should be very familiar. We are simply declaring an array of numbers called “apples.” The next line of code is where it gets good. We declare our variable “totalApples” and set it equal to the return value of this .reduce function. So what is going on in this .reduce? Well, the first argument of any .reduce function is always the callback. This callback is where all data manipulation takes place. The call back takes two arguments: an accumulator and a current value. Let’s observe the arguments.

The accumulator is both your starting and your returned value. This next point is super important: if you give your .reduce function that optional third argument then that is the initial value of your accumulator. Otherwise, your accumulator’s starting value is the first element of your collection. In other words, our starting accumulator value in the above function is 0 because we explicitly declared 0 as the optional third argument. If we didn’t declare that optional third argument, our starting accumulator value would be 3 since that is the first value of our apples collection. The importance of this will become more apparent as you read on. So what is the second argument in this callback? The current value argument.

The ‘current’ argument represents the current value that our .reduce function is on. In other words, the first time around, current = 3. Next, current = 5. Finally, current = 2. Fairly straight forward.

The final argument of .reduce is that optional third argument. In the above example, we declared it as the number 0. However, this third argument can be of any data type we choose. This is huge. This is what makes _.reduce so different from other functions like _.map or _.each. This third argument can be a number, a string, an object, an array, or any other mutable data type you can think of. Why is this so powerful? Well, this allows us to completely transform our arrays into a different data type all together within a single function. For further understanding let us revisit our earlier example only this time, we will start with a slightly more complex data type. We will declare an array of objects describing the color and flavor of the apples. The goal is to end up with a single object telling us how much of each apple we have, how many of each flavor we have, and the total number of apples we have.

let apples = [{color: 'red', flavor: 'sweet'}, 
{color: 'green', flavor: 'sour'},
{color: 'yellow', flavor: 'sweet'},
{color: 'red', flavor: 'sour'},
{color: 'red', flavor: 'sweet'},
{color: 'green', flavor: 'sweet'},
{color: 'green', flavor: 'sour'},
{color: 'yellow', flavor: 'sour'},
{color: 'green', flavor: 'sweet'},
{color: 'green', flavor: 'sour'}]
let totalApples = apples.reduce((accumulate, current) => { accumulate[current.color] ? accumulate[current.color] += 1 : accumulate[current.color] = 1accumulate[current.flavor] ? accumulate[current.flavor] += 1 : accumulate[current.flavor] = 1accumulate["totalApples"] ? accumulate["totalApples"] += 1 : accumulate["totalApples"] = 1
return accumulate
}, {})//totalApples = { "red": 3, "sweet": 5, "totalApples": 10, "green": 5, "sour": 5, "yellow": 2 }

Okay, there’s quite a bit going on here compared to our first example. Let’s take it line-by-line so that you understand what’s going on. Our first line declares an array of apples objects. Each object describes the color and the flavor of the current apple. The next line is the totalApples .reduce function. This time, we initialize our starting value as an empty object, which we will use to reduce our large initial apples array into a single, more readable, object. Let’s look at the body of our callback function.

The first line checks to see if our initial value (the empty object) has a property named the color of our current apple. If it does, then we simply add 1 to the existing value, otherwise we initialize that property and give it a value of one. The first time through, we have an empty object so we don’t have any properties; This means our callback will initialize a property called ‘red’ and assign it a value of 1.

The following lines of code do pretty much the same. We check to see if we have a property corresponding to the current flavor of the apple. If so, we add 1, otherwise initialize the property and assign it a value of one. Every time we iterate through our collection we add 1 to a property called ‘totalApples.’

You will notice that our object is a little messy. Ideally we would have the total of each color in order, and then the total of each flavor, and finally the totalApples property would be the last property in our returned object. However, if you can get past the unorganized nature of our returned object, hopefully you will notice how _.reduce was able to take a massive array of objects, and turn it into a single object holding all of our important information. We now have a single object that tells us how many red, green, yellow, sweet, and sour apples we have. It also gives us the total number of apples.

This was just a brief overview of the power of .reduce. However, hopefully, you have an understanding of the fundamentals of this powerful function.

Some key points to remember:

  1. If no optional 3rd argument is provided to .reduce, then the accumulator argument of our callback will have a value of the first element of our array
  2. That optional 3rd argument can be of any data type. This is the bread and butter of .reduce
  3. If you’re ever getting stuck with .reduce it helps to console.log your accumulator and your current arguments in your callback. More often than not, this will help you see how your function is operating under the hood.

M.
Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade