Transform Arrays With .reduce()

And fewer loops

Bry Zettler
Pandera Labs
5 min readJun 2, 2017

--

This article was close to vanishing into the ether, as in the middle of writing I received an email link to another very solid article about Reduce. However, if this helps even one person in understanding reduce and in writing better iterators, I’ll call it a success. So, here we go.

Whenever writing code that will be performing iterations over an array and transforming it, I first stop and try to think of the best possible way to eliminate any redundancy.

A younger, less experienced me wouldn’t have thought twice about chaining filter and map together. But now my tool of choice is reduce…

Array.reduce()

Array.reduce is, in my opinion, one of the best iterator functions javascript has to offer for transforming an array.

Array.reduce(callback,[initialValue]);
// callback => (acc, item, [idx], [orgArray]) => {};

Let’s walkthrough it real quick... First off, if you’ve never used it before, its an Array.prototype method and therefore must be called on an array. The parameters that it requires to do its job are a callback function and an optional initialValue. The callback is called by every single item in the Array. It takes a maximum of four arguments, two of which are optional (acc, item, [idx], [orgArray]). The two required arguments are acc, the one you need to understand the most, and item.

acc acts as the accumulator for all of the iterations during the reduce cycle. The accumulator is critical to understanding reduce. It is a core concept in recursive functions. It is a stateful value that persists and is passed along through the duration of the reduce function. Each iteration of the reduce cycle returns a modified accumulator value with updates to the state for that iteration. This aides in building up a single result or accumulated value while iterating over a collection. It receives its results from the callback and more than likely will be one of Object, Array, or Number. It defaults to Array[0] or initialValue if one is supplied.

item is the target of the current iteration in the Array
idx is that item’s position in the Array
orgArray is the original Array

Some Gotchas
Reduce must always return the acc
If supplied with an empty Array reduce will return the initialValue

Reduce By Hand

Sometimes I find it helpful to see what an actual method is doing behind the scenes. Here reduce is written as a recursive function.

Hopefully that provides a general understanding of how reduce works. So let’s utilize it to transform some arrays.

How to .filter() & .map() with reduce

Add an if statement.

If you’ve ever had to work with Arrays then you’ve also more then likely had to use .filter() and its relative .map().

Here we filter the records to ones longer than 60 minutes. Then we map over them, creating an extra display property. This works well and is easy to read. However we can do this exact same logic in a single .reduce() call.

First, we check if the record meets our length criteria of 60 minutes. If it doesn't we return the acc as is. This acts as our filter. If it does meet the criteria, then we build up our new acc.

We begin by destructuring the existing acc into a new empty array, then we destructure the record into an empty object, and finally we append the display prop to the new record object. This gives us the exact same result as the .filter().map() code but with one fewer loop. If you needed to do multiple filters during the iterations of the reduce cycle, you would just need to add more if statements.

How to convert an Array to an Object

Create a unique identifier from item and add it to an Object

Another thing you’ve probably come across is attempting to convert an array to an object. Sure, you can use Object.assign or es6 spread operator

But what if you needed more control over the naming of the object keys? Maybe for fast lookups with a unique identifier? You can use reduce for that as well.

Here, we reduce over the array of records, setting the initialValue to an object. As we iterate over the records, we create a unique key inside of the acc from the title and artist while also setting its value to the record. The acc will return an Object whose keys can easily be used to return specific records.

How to remove multiple items from an array

Use reduceRight

A time will come when you’ll want to remove multiple items from an array, at specific indexes and in a single loop, while avoiding items jumping to other indexes. This is where .reduceRight() comes into play. It does exactly the same thing as .reduce() but it acts on the original array from right to left.

How to return a different value than initialValue

Check if on the last index and transform acc

If you ever want to return a different value instead of the initialValue, all you need to do is determine if you’re on the last item of the orgArray and return what value you want.

Here we have an apiResponse and a list of constants that we want to combine for the UI to display. We start by reduceing over the list of constants, then we use Array.prototype.find() to check if the constant was returned by the API. If it was, we append it to the acc object with the constant as its key. If it wasn't, we still append it but we create a default value for it. Every loop will check if idx === (orgArray.length — 1) this will tell us if we have iterated over every item. If we have, we return Object.values(acc) which will result in an array of the new items. Otherwise we return the acc and go onto the next iteration. We started with two arrays, reduced it down to an object with unique keys and default values, then returned an array of the values when on the last item.

Fin…

I hope these examples show you how helpful reduce can be and will encourage you to start utilizing it. If you use it in any other way, I’d love to hear about it.

--

--