Quick Tip: Transform an Array into an Object using .reduce()
Tags: beginners, javascript, functional
Published: 2019-02-17 23:55:49

---
title: Quick Tip: Transform an Array into an Object using .reduce()
published: true
description: The functional tools that Javascript, especially JavaScript arrays provide, have a lot of untapped potential.
tags: beginner, JavaScript, fp, functional
cover_image: https://media.defense.gov/2017/Oct/20/2001830229/1088/820/0/170913-F-FX606-001.JPG
---

I spare you the time of reading some long boring intro, here's the meat of the article:

Let's say you have an array like this:

```js
[
    {id: 1, category: "frontend", title: "All About That Sass"},
    {id: 2, category: "backend", title: "Beam me up, Scotty: Apache Beam tips"},
    {id: 3, category: "frontend", title: "Sanitizing HTML: Going antibactirial on XSS attacks"}
]
```

And you'd like to get an object with categories as keys, mapping to the article id's with that category, like this:

```js
{
    frontend: [1, 3],
    backend: [2]
}
```

You can use our friend [`Array.prototype.reduce`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce) for this.

```js
const posts = [
    {id: 1, category: "frontend", title: "All About That Sass"},
    {id: 2, category: "backend", title: "Beam me up, Scotty: Apache Beam tips"},
    {id: 3, category: "frontend", title: "Sanitizing HTML: Going antibactirial on XSS attacks"}
];

const categoryPosts = posts.reduce((acc, post) => {
    let {id, category} = post;
    return {...acc, [category]: [...(acc[category] || []), id]};
}, {});
```

Alright, let's see how this works.

I think of `reduce` as if it turns my array into a **pipeline**. This pipeline takes some initial value, and applies each value in my array as a separate step, and returns the new value. This value that is passed from step to step is often called the **accumulator**, because it accumulates changes as it goes through the pipeline. The initial value for the accumulator is passed as the second argument to  `reduce`. In this case, it's an empty object. So how are the elements of our array applied to the accumulator? That depends on the function you give to `reduce` as the first argument. Whatever you return from that function, is used as the new value for the accumulator. 


```JavaScript
(acc, post) => {
    let {id, category} = post;
    return {...acc, [category]: [...(acc[category] || [])], id]};
}
```

This function takes the accumulator as its first argument, and an element from the array as its second. The first line extracts the post's category and id into their own variables using [object destructuring](https://dev.to/_elmahdim/destructuring-in-javascript-87n). This is just to give us nice short variable names to work with, making the next line a little bit neater.


```JavaScript
return {...acc, [category]: [...(acc[category] || [])], id]};
```

I used a lot of ES6 syntax in here that not everyone might be familiar win, so let's dig in.


```JavaScript
return {...acc}
```

If we were to just return this, we'd just return the initial value of the accumulator, because this `...` in front of it is called [spread](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax#Spread_in_object_literals). In an object literal, it takes all the properties and values of the given object, and puts them in the newly created object. So all the line above does, is take theproperties our accumulator has, and put them into the object we return.

```JavaScript
return {...acc, [category]: [...(acc[category] || [])], id]};
```

The next thing you'll probably notice is this `[category]:` syntax. It's a [computed property name](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#Computed_property_names). The idea is that you can define a property in an object literal without knowing the property name in advance. In the line above, the property name is whatever the category is.

We want this property to eventually contain an array with all the ids of posts that have this category, so let's have a look at the value we're giving this property:

```JavaScript
[...(acc[category] || [])], id]}
```

Here we have that spread syntax again, but this time in an Array literal. Similar to the object spread syntax, this takes all the values from the array it is given, and acts as if they were written inside this array literal, inserting them at that position in the newly created array.

This gives us quite neat way of defining an array that is just some other array with one or more values appended to it.

```JavaScript
const a = [1, 2, 3];
const b = [...a, 4]; // b = [1, 2, 3, 4]
```

So in our posts example, we'd like to append the post's id to whatever id's our accumulator already has, so we'd just write:
    
```JavaScript
[...acc[category], id]}
```

But what if our accumulator doesn't have any posts for that category yet? (Which will be true at the start for all categories) Then `acc[category]` would be `undefined`, and the spread syntax only works on iterable values like Arrays, so we'd get a `TypeError`.

```JavaScript
[...(acc[category] || [])], id]}
```

So instead, we take the expression `acc[category] || []`, (enclosed in braces so the spread syntax applies to the entire thing. The `||` operator returns the second value in case the first one is falsy (which `undefined` is), so if our accumulator doesn't have any posts with the given category, we'll just spread the empty array, resulting in no values being added before our new id.

So, let's put it all together:

```js
const posts = [
    {id: 1, category: "frontend", title: "All About That Sass"},
    {id: 2, category: "backend", title: "Beam me up, Scotty: Apache Beam tips"},
    {id: 3, category: "frontend", title: "Sanitizing HTML: Going antibactirial on XSS attacks"}
];

const categoryPosts = posts.reduce((acc, post) => {
    let {id, category} = post;
    return {...acc, [category]: [...(acc[category] || []), id]};
}, {});
```

Calling `reduce` on the posts array with an empty object as initial accumulator, for each post we:

- extract the post id and category
- take all the existing properties of the accumulator, and apply the returned value.
- If the accumulator already has an array of id's for the post's category, we append the post's id to it. Otherwise, we create a new empty array for that category, and add our post's id.
- The value we return from the function passed to `redused` is used as the accumulator for the next post in the array, and returned from `reduce` after all posts have been processed.

# Feedback 💬

This is my first somewhat beginner-oriented post, and I'd love **any constructive feedback you have!**. I feel like I overcomplicated this post by using so much ES6 syntax, and then felt the need to explain it all. I think I should have kept that to a minimum, and stuck to the core concept of using `reduce`. I might still write a more focussed version of this post, but for now, this is what I have.

This way of using `reduce` is probably also incredibly obvious to people who have a good understanding of functional programming. But most of my programming life has been spent writing procedural and object oriented code. Map felt intuitive to me quite quickly, but I'm still having little light bulb moments with all the ways I can use `reduce`.