## DEV Community 👩‍💻👨‍💻 is a community of 966,904 amazing developers

We're a place where coders share, stay up-to-date and grow their careers.

Joe Pea

Posted on

# You don't need Array.reduce()

I was reading another dev.to post, Demystifying `Array.reduce()`, but I didn't feel convinced about using `Array.reduce()`.

Maybe I too am not using `Array.reduce()` the right way, but every time I do, I end up disliking it and switching to a simple `for..of` loop.

Up ahead are the three examples from that article, converted to use `for..of` and in my opinion easier to read and cleaner.

Take for example the sum example:

``````const array = [1, 2, 3, 4];
const sum = array.reduce((accumulator, currentItem) => {
return accumulator + currentItem;
}, 0);

// sum = 10
``````

It can be written as

``````const array = [1, 2, 3, 4]
let sum = 0
for (const n of array) sum += n

// sum = 10
``````

That's simpler!

The next example,

``````const trips = [{type: 'car', dist: 42}, {type: 'foot', dist: 3}, {type:'flight', dist: 212}, {type: 'car', dist: 90}, {type: 'foot', dist: 7}]

const distanceByType = trip.reduce((out, curr) => {
const { type, dist } = curr;
if (out[type]) {
out[type] += dist;
} else {
out[type] = dist;
}
return out;
}, {});

// distanceByType = {car: 132, foot: 10, flight: 212};
``````

can be rewritten as

``````const trips = [{type: 'car', dist: 42}, {type: 'foot', dist: 3}, {type:'flight', dist: 212}, {type: 'car', dist: 90}, {type: 'foot', dist: 7}]
const distanceByType = {}

for (const trip of trips) {
const { type, dist } = trip
if (distanceByType[type]) {
distanceByType[type] += dist
} else {
distanceByType[type] = dist
}
}

// distanceByType = {car: 132, foot: 10, flight: 212}
``````

Simple!

``````const pipeOnce = (fn1, fn2) => (args) => (fn2(fn1(args)));
const pipe = (...ops) => ops.reduce(pipeOnce);

const addTwo = a => a + 2;
const mulTwo = a => a * 2;

console.log(addTwoMulTwo(1));  // (1 + 2) * 2 => 6
console.log(addTwoMulTwo(2));  // (2 + 2) * 2 => 8
console.log(addTwoMulTwo(3));  // (3 + 2) * 2 => 10
``````

is a better of example of reduce, but it can be written as

``````const addTwo = a => a + 2;
const mulTwo = a => a * 2;

console.log(addTwoMulTwo(1));  // (1 + 2) * 2 => 6
console.log(addTwoMulTwo(2));  // (2 + 2) * 2 => 8
console.log(addTwoMulTwo(3));  // (3 + 2) * 2 => 10
``````

If we want to pipe an arbitrary number of functions, we can do it with `for..of` too:

``````const pipe = (...fns) => arg => {
for (const fn of fns) arg = fn(arg)
return arg
}

``````

This one isn't as short, but it is easier to understand.

What are some use cases where `Array.reduce()` really shines over alternatives like `for..of`?

Uzair Shamim

One of the reasons I like using reduce is because it prevents accidental mutation of the the original array and it is consistent with how it works and looks (in fact this applies to the other array methods like map and filter).

JavaScript Joel • Edited on

for loops either mutate data or perform side effects, which as a general rule why they are good to avoid.

`map`, `filter`, and `reduce` also allow better code reuse and testability because it can be broken down further than a for loop can.

Example:

``````// modular, reusable, testable!
const add = (a, b) => a + b

``````

You'll also notice all those `let`s go away and become `const`.

Get rid of for loops and it's possible to write your entire program without a single `var` or `let`!

crazy4groovy

I think you mean

``````const add = (a, b) => a + b
``````

You need a seed value.

JavaScript Joel

Nope. That is exactly what I meant.

The seed is optional. If you don't provide a seed, the first item in the array is given as the accumulator.

Run the code!

``````const add = (a, b) => a + b

``````

Sum is just about the only case where reduce is useful, but in reality it should never be passed around like that. Why keep an `add` function around that is only meant to be used together with a `reduce`? Just wrap it once and never use reduce again:

``````const sum = (array) => array.reduce((a, b) => a + b);

sum([1, 2, 3]) //=> 6
``````

Don't tell me `arr.reduce(add)` makes more sense than `sum(arr)` because it doesn't.

In reality you can write `sum` event more efficiently with a regular loop and every part of your code benefits.

Seriously, man? for..of?

``````const myTotalLikes = retrieveAllPosts()
.filter(p => p.user == me)
.map(p => p.likes)
.reduce((acc, like) => acc + like, 0)
``````

Sometimes it's better to use for..of (e.g. when you need some boost iterating over a huge collection you can do all the stuff in one loop) but functional style is much more useful when you are trying to express yourself to your colleagues.

Lewis Cowles

My head nearly exploded looking at that. Map reduce is not a good pattern for application engineering, it's a backend big-unstructured-data pattern.

`retrievePostsFor(me)` would be so much easier to think about as well. Baking in getting all posts and filtering is just not clear unless you have a shallow micro-service code-base, embrace the cascade.

Finally wrap that up in a method

``````function totalLikes(user) {
return likes = retrievePostsFor(user)
.map(p => p.likes)
.reduce((sum, likes) => sum + likes, 0);
}
``````

Lewis Cowles • Edited on

to anyone liking this, it works better if you just send in users. Then it doesn't matter where they come from, and anything with 0 likes just adds items to the list...

In-fact it doesn't need to be a user at all. Just something implementing a likeable interface, which has a method to retrieve likes.

I'm guessing map, filter, fold, reduce etc were born from adopting functional programming methods. Sounds like you're not really into that style (while I totally agree about lack of side effects and mutation). It sounds kind of weak, but I would say to truly get to the heart of your question, work with some Haskell or purescript (or look into lambda calculus), instead of trying to compare JavaScript code.

K (he/him)

Maybe ReasonML could help too, because it's closer to JavaScript.

Peter

I'd agree maybe it's that I'm used to for loops but they read easier for me and I know better what's going on.

I'd also say it's the same for the majority of JS users (at least from my experience) so when you got a bigger team the safer bet is to use for loops. Helps to make the code easier to understand for more people.

I would say that the absence of side effects is often overvalued when talking about this. Though I understand where people are coming from :)

jtenner

I use `Array.prototype.reduce` a lot. The reason why is because v8 and firefox does a very good job of optimizing reduce calls when it gets optimized.

Often in the case of clarity over speed, using `for..of` loops is the best. Sometimes, it's not always about clarity.

Joe Pea

Good point. Thanks for that perspective!

Nicolás Wernli

First example could be simpler with reduce, I mean, if you use n as variable in the for version, why not using n in the reduce one?

const array = [1, 2, 3, 4];
const sum = array.reduce((a, n) => a + n, 0);

Theofanis Despoudis

Actually, this is better as you can extract the reducer part
`(a, n) => a + n` as a function. The other way is not reusable.

Enrique Moreno Tent

Your first example can be solved like this:

``````add = (a, b) => a + b
``````

Your second example can be solved like this:

``````getDist = (obj, type) => type in obj ? obj[type] : 0

addTrip = (acc, trip) => ({ ...acc,
...{[trip.type]: (getDist(acc, trip.type) + trip.dist)}
})

``````

Both example look easier with reduce, I think

Joe Pea

Those are shorter, but at a glance it still takes me more time to understand it than the for..of loops. Maybe it's just how my mind is trained.

Kushan Joshi • Edited on

Keeping the functional programming jargon aside, reduce might be difficult to read for people familiar with imperative style of programming. You need to focus on the part that reduce reduces the cognitive load from your head (of course after you understand how it works). You will appreciate that all you need to care about is the function that you pass to the reduce. There is not outer references that you need to be bothered about. You can even move this function to a new file and it would make sense to any fellow developer( It’s called code decoupling), because everything is self contained! no need to worry about some variable in the outer context. You can google more about the benefits of code decoupling.

Andrew Zhurov

Mutation transfers a var X from state A to state B, so now, when we intend to use X we need to check is it A or B.
We actually do mutations for 'complex behaviour' - ability to launch different execution branches for the same input signals, which to launch is determined by current state of X. In such case X would be 'control state' (FSM term).
It is the appliance where it's truly needed, others are adding accidental complexity to simple data/value transformation.
Thanks for the post, got me thinking

Mihail Malo

It also helps a lot when one has a phobia of statements.

``````const panic = err => {
throw err // oh no, a statement!
}
const apply = (state, event, context) =>
(this.reducers[event.type] ||
panic(new Error(`Unknown event type: \${event.type}`)))(
state,
event,
context
)

const applyAll = (state, events, context) =>
events.reduce((state, event) => apply(state, event, context), state)

const replay = (events, context) => applyAll(this.initialState, events, context)

``````

Andrew Zhurov

Is this correct?

``````const pipeOnce = (fn1, fn2) => (args) => (fn2(fn1(args)));
const pipe = (...ops) => ops.reduce(pipeOnce);
``````

It seems for me pipeOnce should be

``````(acc, fn) => fn(acc)
``````

Though it would not be 'pipeOnce' by semantic anymore:)

Joe Pea

Heh, well this shows that thinking about it is more complicated than the for..of loops.

ConaxLiu • Edited on

I haven't seen any mention of forEach in this thread. So I wonder why do we still need reduce when forEach can achieve exactly the same result and number of code lines?

``````var trips = [{type: 'car', dist: 42}, {type: 'foot', dist: 3}, {type:'flight', dist: 212}, {type: 'car', dist: 90}, {type: 'foot', dist: 7}]

var distanceByType = {};

trips.forEach(curr => {
const { type, dist } = curr;
if (distanceByType[type]) {
distanceByType[type] += dist;
} else {
distanceByType[type] = dist;
}
});

console.log(distanceByType);
``````

Joe Pea

Totally! And that is also much more readable!

AjayMalhotra

good informations.

Mihail Malo
``````let sum = 0
``````

Ah, but now the sum is mutable! Who knows what will happen to it!

## Take a look at this:

Go to your customization settings to nudge your home feed to show content more relevant to your developer experience level. 🛠