I love `Array.prototype.reduce()`. I love the power and flexibility it brings me. Unfortunately, this Array prototype method confuses many developers, and as a result, isn’t used as often as it probably should be.
Before diving into the many uses for this Array prototype method, let’s take a look at the function signature.
Array.prototype.reduce(reducerFunction, startingValue);
And the reducerFunction signature looks like so:
function reducerFunction(accumulator, currentValue, currentIndex, sourceArray);
Let’s try to shed away some of the confusing terminology. I’ll be honest. When I was first started learning about this stuff it certainly made this function seem really intimidating and complicated. `Array.prototype.reduce()` is an iterator, in the same category as `filter()`, `map()`, `forEach()`, `some()`, `every()`, and many others. It’s a glorified `for` loop that does something with each item of the array.
Many of the uses for `reduce()` involve making something smaller, thereby “reducing” it to something less than it was. This often times includes changing the array to a different data structure altogether.
Looking at the `reduceFunction`, you’ll see that there is an `accumulator` argument. This is what really makes `reduce()` so special, because it comes with a built in a way of slowly building up a value without needing to instantiate another variable. Instead, you slowly modify the `accumulator` value, which starts as `startingValue`. The `accumulator` is slowly “accumulating” changes with each iteration.
Flatten an array
const comments = things.reduce((accumulator, thing) => {
return accumulator.concat(thing.nestedThingArray)
}, []);
Quick sum or average
const total = [1, 2, 3, 4, 5].reduce((accumulator, item) => {
return accumulator + item;
}, 0);
const average = [1, 2, 3, 4, 5].reduce((accumulator, item, itemIndex, sourceArray) => {
if (itemIndex === sourceArray.length - 1) {
return (accumulator + item)/sourceArray.length;
}
return accumulator + item;
}, 0);
Create a dictionary
Let’s say you’re needing to find specific objects in an array over and over again, perhaps in another loop. You can easily get into O n^2 territory or beyond. One real easy optimization to get you back into linear complexity land is to create a dictionary keyed off of the value you are looking for in the array.
const things = [
{ id: 'a', otherThings: { nested: "deep" } },
{ id: 'b', moreThings: { nested: "somewhere" } },
{ id: 'c', evenMoreThings: { nested: "beyond" } }
];
things.reduce((acc, thing) => {
acc[thing.id] = thing;
return acc;
}, {});
Count things
[
{ type: 'A' },
{ type: 'A' },
{ type: 'B' }
].reduce((acc, item) => {
if (!acc[item.type]) {
acc[item.type] = 0;
}
acc[item.type] += 1;
return acc;
}, {});
Transform array to some other complicated structure
No need for an example here, but you could use `reduce()` to change an array structure to just about any other complicated structure you can think of.
awesome