JavaScript Array.reduce — Let’s understand it once and for all
Most JavaScript developers avoid using Array.reduce like it’s the plague, and I don’t blame them. It can be confusing at times, but it doesn’t have to be.
Most tutorials teach you how to sum up an array of numbers which is fine, but in real life, you are probably going to be dealing with more complex data.
So, in this tutorial, I am going to go over how to use Array.reduce, when to use it, and prove to you that Array.reduce is fairly simple.
Example one: Summing up numbers.
I know, I know, such a classic textbook example, but we have to build up from somewhere!
const arr = [1, 2, 3, 4, 5, 6, 7]
const initialValue = 0
const sumFunction = (acc, current) => {
return acc + current
}
const sum = arr.reduce(sumFunction, initialValue)
Let’s break this down now.
We start off with our data, which in this case is an array of integers. Next, we have the initial value. After that, we create our sum function, which takes two arguments: the accumulator and the current value. It returns the sum of the previous value and the current value. Lastly, we call Array.reduce with the sum function as the first argument and the initial value as the second argument.
When the sum function runs for the first time, the accumulator is set to the initial value, which in our case is 0. On each subsequent run, the accumulator is updated to a new value that is the sum of the previous value and the current value.
Here’s what happens on each run:
First run => accumulator = 0
Second run => accumulator = 0 + 1 => 1
Third run => accumulator = 1 + 2 => 3
Fourth run => accumulator = 3 + 3 => 6
Fifth run => accumulator = 6 + 4 => 10
Sixth run => accumulator = 10 + 5 => 15
Seventh run => accumulator = 15 + 6 => 21
Last run => accumulator = 21 + 7 => 28
Now that we have a basic understanding, let’s delve into something a bit more complex.
Example 2: Objects
Picture this: We conducted a big survey to find out which JavaScript frameworks are used the most. A whopping 10,000 people responded to our survey, giving us a long list of results. Now, we need to organize that list properly and make sense of all the information we gathered.
const bestFrameworkOrLibrary = [
'Vanilla',
"React",
"React",
"Angular",
"Ember",
"jQuery",
"jQuery",
"jQuery",
"...."
]
We want to tidy up the list in a specific way. We need to create an object where each JavaScript framework is a key, and the value associated with each key is the number of times that framework appears in the list. It’s important to note that each framework should only appear once as a key in the object.
To the rescue comes Array.reduce.
// inital value
const initialValue = {}
const accumulate = (accumulator, currentItem) => {
// check to see of currentItem exists in the object
if (!accumulator[currentItem]) {
// if it doesn't exist, let's add it and give it an initial value of 1
accumulator[currentItem] = 1
} else {
// otherwise let's increment the value
accumulator[currentItem] += 1
}
// return our object. Always return the accumulator
return accumulator
}
const result = bestFrameworkOrLibrary.reduce(accumulate, initialValue)
As before, we have our data, the initial value, the callback function and the Array.reduce that takes it our callback and the initial value.
The minor difference here is that our initial value is now an empty object. That’s all.
Our callback function does some logic that checks to see if the currentItem (framework) exists in the object, if it doesn’t, we add it and set its value to 1, otherwise we increment the value by 1.
Example 3: Flattening an array of object.
Say we have an an array that looks something like this:
const data = [
{
name: "Eli",
hobbies: [
'coding',
'reading',
'hiking'
]
},
{
name: "John",
hobbies: [
'dancing',
'reading',
'hiking'
],
},
{
name: "Sam",
hobbies: [
'cooking',
'swimming',
'hunting'
]
}
]
The goal is to find all of the unique hobbies among all of the users.
Once again, Array.reduce comes to the rescue.
// inital value
const initValue = []
const accum = ((acc, person) => {
// loop through each person hobbies
person.hobbies.forEach((hobby) => {
// if hobby doesn't exist in the array, I added it to the end.
if (!acc.includes(hobby))
acc.push(hobby)
})
// return our accumulator
return acc
})
const uniqueHobbies = data.reduce(accum, initValue)
Inside the accumulator function, we're simply going through each person's list of hobbies. We check if a particular hobby is already present in the accumulator. If it's not, we add it to the accumulator.
Now, here's the thing: you don't always have to use Array.reduce. Sometimes, Array.filter or Array.map can do the job just fine. However, there's a situation where Array.reduce might seem like a better choice, and that's when we want to optimize performance.
Say you want to filter data. You’d probably do something like this, right?
bestFrameworkOrLibrary.filter((library) => library.endsWith("y"))
Very valid approach.
Now, let’s see how we can do the same exact thing with Array.reduce.
bestFrameworkOrLibrary.reduce((acc, lib) => {
if (lib.endsWith('y')) {
acc.push(lib)
}
return acc
}, [])
This doesn’t look so bad, I think Array.filter has a slightly better readability, but that’s not the point.
The reason why I did this comparison was to ask you the following question, which one do you think is faster?
I’ll show you!
HOLY MOTHER OF JS, filtering data took us about 7.5ms while using reduce took us only 0.26ms 😱 Array.reduce did the same task, but 30 times faster than Array.filter
Now, you may ask why such a drastic difference? The simple answer is that it has to do with the way data is added into the new array.
.push is going to light years ahead in speed because all it’s doing is adding items to the the end, where is Array.filter needs to loop through the whole array, filter items and than create a new array.
In Array.reduce all we did was loop, and push to the end, that’s it, we didn’t have to remove anything.
All in all, Array.reduce like a Swiss Army knife in JavaScript — it’s pretty handy!
In this article, we’ve used it for all sorts of things: adding numbers together, counting up votes for favorite JavaScript frameworks, smoothing out a lumpy list of objects, and even outrunning Array.filter in a speed race.
Sure, Array.reduce might seem a little tricky at first — like learning to ride a bike. But once you get the hang of it, you’ll see how it can help you work with lists in a cool and efficient way. It can be a real game-changer in some cases where other methods might not be the best fit.
But remember, just like your bike isn’t the best way to cross an ocean, Array.reduce isn’t the solution for every problem. It’s important to think about what you’re trying to do and pick the best tool for the job. And just as important, make sure your code is easy for others to read and understand.
So, next time you’re coding in JavaScript, don’t forget about Array.reduce. It’s a powerful tool to have in your coding backpack, ready to use when the right problem comes along!