Using Array.prototype.reduce to form objects using JavaScript

Vinicius Marchesin Araujo
3 min readOct 16, 2018

--

A common yet not trivial problem that any developer have encountered (or is yet to encounter) is counting elements. You have a dataset, and you want to count things inside it. How many kids in each grade at a school? How many items of each kind do you have in stock? How many pizzas of each flavor did you eat in your entire life?

How would you even retrieve this kind of data? Do you keep a diary for everytime you eat pizza?

There’s a bunch of ways to approach this problem, but let keep this simple for the sake of the demonstration. As we know the Array.prototype.reduce is a handy method for reducing datasets into meaningful values. One thing that isn’t obvious is that you can reduce arrays to objects as well, not just numbers. How do we do that?

Everyone knows you can reduce arrays to numbers. But did you know you can reduce them to objects as well?

First, a quick overview of how reduce works.

const arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
const sum = arr.reduce((acc, value) => value + acc, 0)
console.log(sum) // 45

The reduce method receives two arguments: a function and an initial value. The function will run run for every value in the array, and receives two arguments as well: the accumulator, or acc, and the current value. The return of this function is then passed as the acc for the next iteration, until the last element. For the first iteration the initial value (the second argument of reduce) is used as the accumulator. In this case we start with a value of 0, and sum each element of the array until we have the value 45 at the end.

Now let’s solve a simple problem. We have an array with fruits, and we want to count how many fruits of each kind are inside the array.

const FRUITS = ["banana", "apple", "orange", "banana", "orange", "apple", "apple", "orange", "orange", "banana", "orange", "banana"]

A simple and effective way is to iterate each element and save the count to an object. The complexity is O(N) and it can’t get much better than that.

let total = {}
for (fruit of FRUITS) {
total[fruit] = (total[fruit] || 0) + 1
}
console.log(total) // { banana: 4, apple: 3, orange: 5}

The code above is straightforward: if the property exists increase it by one, and if it doesn’t declare it as 0 and then increase it by one (because we can’t do undefined + 1).

As good as this is, we can also solve this using functional JavaScript. Let’s see how to use the reduce method to achieve the same result.

const total = FRUITS.reduce((map, fruit) => ({
...map,
[fruit]: (map[fruit] || 0) + 1,
}), {})
console.log(total) // { banana: 4, apple: 3, orange: 5}

This is much more elegant, mainly due to the fact that you can transform the result and chain it to another method, either filtering or modifying it. Let’s break down what is happening here:

We start with an empty object. This will be passed as the accumulator map to our function during the first iteration.

Now we make use of two ES6 syntax features: spread syntax and computed properties [fruit]. In short what they do is: spread will fill the object with all the current properties inside the object and enable us to overwrite any of them, and computed properties enables us to use the value of a variable as the actual key of an object.

So now for each iteration we spread the accumulator and increase the value of the fruit in the current iteration. At the end we return the full object and achieve the same result as the iterative for alternative, at the same complexity rate.

--

--

Vinicius Marchesin Araujo
Vinicius Marchesin Araujo

Written by Vinicius Marchesin Araujo

Front-end developer and dolphin impersonator. Currently working as a JavaScript Developer at @Socialbakers in Prague. | https://vmarches.in

Responses (4)