Have you ever wrote a for loop to iterate over the array to get some value(s) out of it? If yes, then most probably, you could just use reduce, map, or filter instead. In this article, we won’t focus on the latter two, so let’s talk about reduce.
As the documentation says, reduce() executes a reducer function on each element of the array. Reducer is a function that takes accumulator (which is a temporary result) and current value from iteration. It does what it needs with them, and the returned value becomes the new accumulator. When we achieve the end of the array, the accumulator is returned as the result of the reduce function. It’s worth mentioning that reduce is also a core of many functional languages where it can be often found under the name fold or aggregate. That’s why the best uses of reduce are when it can provide a simple replacement of the for loop in an elegant and functional way instead of with every possible loop.
According to MDN, the syntax is as follows:
<em>arr.reduce(callback( accumulator, currentValue, [, index[, array]] )[, initialValue])</em>
The callback is a reducer function, and as we said, it takes the accumulator and current value from iteration. Additionally, we can also get an index of the current element and source array, but these two aren’t used often. Also, we can define our initial accumulator value under initialValue. If we don’t provide it, the first value from an array will become an initial value.
It’s also worth noting, there is also a reduceRight() function. It does the same thing but in the opposite direction by starting from the end of an array.
Enough of theory. Let’s get to the practical part. Here, you’ll find a few examples of how reduce can be used with an explanation of how it’s done and why it works. You shouldn’t consider all of these as a go-to solution for each of these problems, but more as a brain teaser and a way to get along with reduce.
Sum/difference/product/quotient of elements
The most popular use case of reduce and probably the only noncontroversial one. The code here is very simple:
var sum = array.reduce((acc, val) => acc + val); var diff = array.reduce((acc, val) => acc - val); var product = array.reduce((acc, val) => acc * val); var quotient = array.reduce((acc, val) => acc / val);
Because acc always contains a previous value in the first iteration first value, we can safely get the result by just doing a proper operation with the current value.
Flattening an array
Another popular use case, but it’s a bit outdated since we’ve gotten a flat() function. However, if you’d like to take a look at how to do it in an old-school way because, e.g., you’re writing for Internet Explorer 11, here’s the code:
var flatArray = array.reduce((acc, val) => acc.concat(val), );
Our accumulator starts with an empty array, and later we’re linking a current nested array to it. In this way, as the final result, we get the flat array. Just remember, this code only works for one level of nesting!
Function pipe, in simple words, is a merge of many functions working on their results. You start with the first function, and it returns a result that becomes an argument for the next function, which returns a result, and it goes on and on until we reach the last function. What’s worth knowing is that when we’re using the pipe function and providing it a few functions we want to run, it should also return us a function and not a value. Here’s how we can do it with reduce:
var pipe = (...functions) => value => functions.reduce((acc, func) => func(acc), value);
How does it work? Our pipe is a function that takes multiple functions as an argument. It returns a function that takes a value and does a reduce on originally provided functions, running each of them and taking the return value to the accumulator. I know it may be a bit confusing, so here is a usage example:
var add2AndStringify = pipe(x => x + 2, x => '' + x) add2AndStringify(10); // result: "12"
This is the worst usage of reduce, but still an interesting one. That’s why I wanted to share it with you. Of course, I don’t recommend using it. You’d be better off using sort() instead because it’s faster, but it serves an educational purpose. It’s nowhere close to being the optimal way.
var sortedArray = array.reduce((acc, val) => [...acc.filter(x => x <= val), val, ...acc.filter(x => x > val)], );
It works in such a way that we’re creating a new array for every value. We’re first giving all elements smaller or equal, to ensure the algorithm’s stability, to current, then the current and the rest of the elements. If you know the insert sort algorithm, it should sound familiar to you. However, please don’t use it in real, noneducational projects.
Should we use reduce?
It’s a difficult question to answer because it depends on your use case. As you can see in the examples above, sometimes we’ve simplified the code, but it could become unreadable in other cases.
Our priority in coding should be to make code readable for every other developer. When working in a team, it’s essential to create a self-explanatory code instead of confusing mumbo-jumbo that is readable only to its author.
Another thing you should consider before using reduce is whether the functionality hasn’t been already implemented in a more straightforward, maybe even better, way. It’s not worth writing something from scratch if it’s already been done, especially if it’s in a language’s standard library.