"Sonic reducer, ain't no loser" (Sonic Reducer by The Dead Boys)
I’ll be honest: I didn't always like to use reduce().
Not because I couldn’t use it — but because my brain was wired to just reach for other methods like forEach(), for() or map(). And let's be real, anytime you see documentation (side eyeing MDN), it always seems to use the simplest example, taking an array of numbers and adding them together for one value.
But reducers are so much more versatile and powerful than just being a calculator. And maybe part of the reason we think of it that way is the terminology used in the function definition.
Now there are a lot of blog posts out there talking about how to use reduce(), so I'm not breaking any ground here. I'm just putting my own spin on it.
The accumulator
You've probably seen this example everywhere. And it's easy to see why, it's the simplest way to explain how it reduces a group of datapoints into one.
const numbers = [1, 2, 3, 4];
const sum = numbers.reduce((total, num) => {
return total + num;
}, 0);
console.log(sum); // 10
Because that first argument to the callback is referred to as the accumulator it's easy to see why many examples use this calculator scenario.
At this point you might be thinking:
“Cool… but I could’ve just used
.forEach()or a loop.”
You’re not wrong.
But this is just the warm-up.
Other math-like ways to use it include finding the min or max value. Now Javascript has native methods like Math.min() and Math.max() that can take values to return the min/max. However, what if you have a more complex data structure that includes a value you want to compare.
// find lowest price
const products = [
{
name: "Thing 1",
price: 12.99,
},
{
name: "Thing 2",
price: 5.75,
},
{
name: "Thing 3",
price: 20.25,
},
{
name: "Thing 4",
price: 3.99,
},
];
const lowestPriced = products.reduce((acc, current) => {
if (!acc.price || current.price < acc.price) {
return current;
}
return acc;
}, {});
console.log(`lowest price: ${lowestPriced.name} is $${lowestPriced.price}`);
// lowest price: Thing 4 is $3.99
To reduce or not reduce, that is the question
At its core, reduce() takes an array and turns it into something else. So it doesn't have to just return a single value. Sometimes we're not actually reducing the input, but just transforming it and rolling out.
That “something else” could be:
- a number
- an object
- a new array
- more advanced data structures like Set() and Map() objects
Once that clicks for you, reduce() goes from confusing to kind of magical. And more importantly, it becomes one of the most powerful tools you have for transforming data.
"A wizard is never late, nor is he early, he arrives precisely when he means to." - Gandalf the Grey
Where reduce() Gets Interesting: Transforming Data
This is where reduce() earns its keep.
Example: Grouping Data
Let’s say you have a list of people:
const people = [
{ name: "Luke", role: "rebel" },
{ name: "Leia", role: "rebel" },
{ name: "Darth Vader", role: "empire" }
];
And you want this:
{
rebel: ["Luke", "Leia"],
empire: ["Darth Vader"]
}
Here’s the reduce() solution:
const grouped = people.reduce((acc, person) => {
const { role, name } = person;
// if acc doesn't have the role, create it
if (!acc[role]) {
acc[role] = [];
}
// now push the name into that role's array
acc[role].push(name);
return acc;
}, {});
console.log(grouped);
This is where reduce() shines:
- You start with an empty object
{} - Build it up step-by-step
- End with a completely transformed structure
The Mental Model That Helped Me
This is the part that finally made it click for me:
The accumulator is just a “thing you’re building.”
That’s it.
- Want a number? Start with
0 - Want an array? Start with
[] - Want an object? Start with
{} - Want a Map? Start with
new Map()
Everything else is just: 👉 “How do I update this thing for each item?”
A Slightly More Advanced Example: Frequency Map
Let’s count how many times each value appears:
const fruits = ["apple", "banana", "apple", "orange", "banana", "apple"];
const count = fruits.reduce((acc, fruit) => {
acc[fruit] = (acc[fruit] || 0) + 1;
return acc;
}, {});
console.log(count);
// { apple: 3, banana: 2, orange: 1 }
Frequency maps can be very useful in algorithms where you need to keep track of values in that way.
Being able to group the data in a way that allows you to easily access it later is also an advantage. In this case, using a Map() object allows us to group data so that we can easily reference it by a specific key.
In this example we have employee names and their departments. If we wanted to query the data by department, we'd have to run a filter() on the data every time to only return one department. And if you want all departments displayed you need to run that filter for as many times as you have departments. That can be expensive.
By creating a new object that organizes these employees by department, we have one lookup we need to do by department name.
const employees = [
{ name: "John Doe", department: "accounting" },
{ name: "Jane Calculator", department: "accounting" },
{ name: "Dave Spreadsheet", department: "accounting" },
{ name: "Mike Python", department: "software" },
{ name: "Emily Rust", department: "software" },
{ name: "Terry Typescript", department: "software" },
{ name: "Max Headroom", department: "customer relations" },
];
// function to group employees by department
function GroupUsersByDepartment(allUsers) {
return allUsers.reduce((acc, user) => {
if (!acc.has(user.department)) {
acc.set(user.department, [user.name]);
} else {
acc.set(user.department, [...acc.get(user.department), user.name]);
}
return acc;
}, new Map());
}
When Not to Use reduce()
Just because you can reduce() doesn’t mean you should.
If your code looks like this:
const result = array.reduce((acc, item) => {
// 20 lines of logic with multiple if() statements
}, {});
You might be writing a future headache.
Sometimes:
.map()is clearer.filter()is cleaner- a simple loop is more readable
There’s no award for “most clever use of reduce.”
A Quick Rule of Thumb
Use reduce() when:
- You’re transforming data into a different shape
- You need to accumulate results over time
- You’d otherwise create and mutate a variable outside a loop
Avoid it when:
- It makes your code harder to read
- You’re forcing it just to be “functional”
Final Thoughts
For me, reduce() went from:
“I will never use this in real life”
to:
“Okay… this is actually really useful.”
The turning point wasn’t memorizing syntax — it was understanding the idea: 👉 You’re just building something step-by-step.
Once you get that, everything else falls into place.
If you’ve been avoiding reduce(), try using it for one small transformation this week.
Not because you have to — but because it’s a tool worth having when things get a little more complex.
And hey, worst case?
You go back to your trusty for loop. No shame in that.