Understanding JavaScript’s Array.GroupBy
Published: 2022-04-27 15:19:39

**Written by [Chris Laughlin](https://blog.logrocket.com/author/chris-laughlin/)✏️**

The JavaScript specification continues to grow and advance to meet the needs of developers who use the language. ECMAScript is the standard that defines the different APIs that can be used when coding with JavaScript.

There have been several different ECMAScript versions over the years starting with version 1 in 1997 up to the most recent version 12 in 2021\. Each version aims to add more API’s, improve on existing API’s and ensure that the language remains relevant.

The process of adding a new API to the language involves a proposal and multiple approval stages from Stage 0, where the proposal is planned to be presented to the EMCA committee by a TC39 champion, or presented to the committee and not rejected definitively to Stage 4 where the proposal will be included in the next ECMAScript release.

In June 2021 Justin Ridgewell raised a proposal for adding `groupBy` to the `Array` API. Grouping data is very common, but currently unavailable in the standard JavaScript `Array` API, and previously, developers had to build their own solution or use a third-party library.

However, this proposal is currently in Stage 3, which means it’s considered complete and no further work is possible without implementation experience, significant usage, and external feedback.

This means it should make it into the standard soon. So, let's take a look at the proposal, alternatives to the proposal, and how we could build our own implementation, including:

*   Grouping data with `[groupBy]`
*   Alternatives to `[groupBy`
*   Create your own `[groupBy]`

## Grouping data with `groupBy`

Before we can start using `groupBy`, we need some data to group. Most of the time when you want to group data, you want to take one or more attributes of that data and organize it by that attribute. For our example, let's take an array of dogs:

```js
const DOGS = [
 {
  name: 'Groucho Barks',
  breed: 'German Shepherd',
  age: 1
 },
 {
  name: 'Pepper',
  breed: 'Shih Tzu',
  age: 3
 },
 {
  name: 'Bark Twain',
  breed: 'Dachshund',
  age: 5
 },
 {
  name: 'Jimmy Chew',
  breed: 'Shih Tzu',
  age: 10
 },
 {
  name: 'Pup Tar',
  breed: 'Dachshund',
  age: 2
 },
]
```

Our array of dogs is made up of an object for each dog, and each dog has a name, breed, and age. The breed is the most common attribute, so we will use this to group the data. You can also use age to get dogs of the same age.

You can also use the name, however in most cases, the names would not match and not group anything.

So, let's see how we can group the data using the proposal:

```js
const byBreed = dogs.groupBy(dog => {
 return dog.breed;
});
```

We can use the new `groupBy` function by calling it on the array instance, just like using a `map`, `filter`, or `reduce` function. `groupBy` takes a callback function which is called for each element in the array in ascending order.

The `groupBy` function then returns a new object where each key is the different breeds and the value is an array of all the matching dogs. If we were to log the `byBreed` variable, it would look like the code below:

```js
{
    "German Shepherd": [
        {
            "name": "Groucho Barks",
            "breed": "German Shepherd",
            "age": 1
        }
    ],
    "Shih Tzu": [
        {
            "name": "Pepper",
            "breed": "Shih Tzu",
            "age": 3
        },
        {
            "name": "Jimmy Chew",
            "breed": "Shih Tzu",
            "age": 10
        }
    ],
    "Dachshund": [
        {
            "name": "Bark Twain",
            "breed": "Dachshund",
            "age": 5
        },
        {
            "name": "Pup Tar",
            "breed": "Dachshund",
            "age": 2
        }
    ]
} 
```

As the `groupBy` array API is still in Stage 3, you cannot use it without a polyfill such as the [core-js](https://github.com/zloirock/core-js#array-grouping) polyfill. But, if you don't want to wait or want to use a polyfill, what are your other options?

## Alternatives to `groupBy`

### Using Lodash

[Lodash](https://blog.logrocket.com/how-and-when-to-debounce-or-throttle-in-react/#using-lodash-debounce) is the most well-known utility library for JavaScript, and was created to tackle many of the missing API’s that did not exist in older versions of JavaScript.

While many of the API’s now exist, people still use lodash when building applications. Lodash has a [`groupBy`](https://lodash.com/docs/4.17.15#groupBy) [function](https://lodash.com/docs/4.17.15#groupBy) that can be passed as an array and a callback function. We can see below how we can achieve our dog's grouping example using Lodash:

```js
import groupBy from 'lodash.groupby';

const byBreed = groupBy(dogs, dog => {
  return dog.breed;
});
```

This generates the same result as the `groupBy` proposal, but the main difference with using the Lodash version is the need to import the Lodash package and calling the function passing in the array instead of calling the function on the array.

### Using Ramda

[Ramda](https://ramdajs.com/) is another Javascript utility library, and its main difference from Lodash is its functional focus. Ramda is functional programming as a first-class citizen library, and you can easily curry the utility functions.

In the below example, it's hard to see any difference between it and using Lodash:

```js
import R from 'ramda';

const byBreed = R.groupBy(function(dog) {
 return dog.breed
});

byBreed(DOGS);  
```

In this example, we create a `byBreed` function, which we can later call with the list of dogs. We can also pass in the dogs when we call Ramda’s `groupBy`:

```js
R.groupBy(dog => dog.breed, DOGS);
```

This archives the same result, but if we use Ramda’s functional nature, we can combine multiple functions:

```js
const byBreed = R.groupBy(function(dog) {
 return dog.breed
});

const reverseName = R.map(function(dog) {
  return {
    ...dog,
    name: dog.name.split('').reverse().join('')
  }
})

const processDogs = R.compose(byBreed, reverseName)
processDogs(DOGS);
```

In this example, we can reverse each of the dogs’ names then group them and make this into a reusable function.

## Create your own `groupBy`

Adding an external library like Lodash or Ramda can have pros and cons. The pros include the additional utilities that the libraries provide. However, the cons include additional bundle size for the end-user and the overhead of managing the third-party dependencies.

As the `groupBy` function is not currently in the core language, you can create your own `groupBy` function you can use until the official version releases. Let's look at how we could create our version:

```js
const groupBy = (list, key) => {
    return list.reduce((prev, curr) => {
        return {
            ...prev,
            [curr[key]]: [
                ...(prev[key] || []),
                curr, 
            ]
        }    
    }, {})
}
groupBy(DOGS, 'breed')
```

In the above example, we create a new function that takes in a list and a key. This key is what we will group on. We then use the [`Array.reduce`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce) [function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce) to do our grouping.

Our `reduce` turns the array of dogs into an object, and then iterates over each dog and adds them to the object. If the breed (key) does not exist on the object, it will be created. The value of the object key is an array where the breed is added.

## Conclusion

`groupBy` is a small addition to the language but by digging into it, we can see how the JavaScript proposal process works, how existing libraries tackled the challenge, and how we can create our own versions of a function.

---

## [LogRocket](https://logrocket.com/signup/): Debug JavaScript errors more easily by understanding the context

Debugging code is always a tedious task. But the more you understand your errors the easier it is to fix them.

[LogRocket](https://logrocket.com/signup/) allows you to understand these errors in new and unique ways. Our frontend monitoring solution tracks user engagement with your JavaScript frontends to give you the ability to find out exactly what the user did that led to an error.

![LogRocket Dashboard Free Trial Banner](https://blog.logrocket.com/wp-content/uploads/2020/06/reproduce-javascript-errors.gif)

LogRocket records console logs, page load times, stacktraces, slow network requests/responses with headers + bodies, browser metadata, and custom logs. Understanding the impact of your JavaScript code will never be easier!

[Try it for free](https://logrocket.com/signup/).