Chris Laughlin JavaScript nerd with 10 plus years of experience in web development. I like tech, coffee and photography. I can usually be found at my desk in the dark making the world a better place, one arrow function at a time.

Understanding JavaScript’s Array.Group and Array.GroupToMap

6 min read 1897

Understanding JavaScript's Array.Group and Array.GroupToMap

Editor’s note: This guide to understanding JavaScript’s Array.Group and Array.GroupToMap was last updated on 9 January 2023 to reflect changes to the API’s proposal. This update also includes sections comparing the two methods, their benefits, and more information about the most efficient way to group arrays. 

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

There have been several different ES versions over the years, and each version aims to add more APIs, improve on existing APIs, 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 Zero, 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 Four where the proposal will be included in the next ES release.

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

However, this proposal, which was formerly known as Array.GroupBy, is currently in Stage Three. This 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 group and groupToMap and how we could build our own implementation.

Jump ahead:

Grouping data with group

Moreover, since the group and groupToMap array methods are still in the proposal stage, we can’t use them in our JavaScript projects. However, if we use polyfill, browsers will understand what those methods do and run them for us without throwing an error whenever we use them.

Simply put, a polyfill is a code that implements a feature on web browsers that do not natively support the feature. The core-js is a robust polyfill that we can use to make the group and groupToMap available in the browser.

To get started with core-js, we can run the following code in our project to install the library:

// Terminal
npm install --save [email protected]

Next, we should import it into the file where we want to use the group and groupToMap method:

// JavaScript
// polyfill all `core-js` features, including early-stage proposals:
import "core-js";

For a quick start, you can view an example below:

Array Group Method Example

Array Group Method Example by bonarhyme using core-js, react, react-dom, react-scripts

Creating an array to group

Before we can start using group, we need some data to group. When you want to group data, you usually 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:

// Javascript 
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 name. However, in most cases, the names would not match or group anything. So, let’s see how we can group the data using the proposal:

const byBreed = DOGS.group(dog => {
 return dog.breed;
});

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

The group function 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:

// Javascript
// Value in console

{
    "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
        }
    ]
} 

Here is the group method in been used in a React project:

Array Group Method Example

Array Group Method Example by bonarhyme using core-js, react, react-dom, react-scripts


Grouping data with groupToMap

Like the previous section, you can check out the example below for a quick start:

Array GroupToMap Map Method

Array GroupToMap Map Method by bonarhyme using core-js, react, react-dom, react-scripts

The groupToMap() method groups the elements in an array using the values returned by its callback function. It returns a Map with the unique values from the callback function as keys, which can be used to access the array of elements in each group. Complex types, such as objects, can be used as keys with the groupToMap() method.

The method is most useful when grouping elements associated with an object, particularly when that object might change over time. For our example, let’s take an array of athletes:

const ATHLETES = [
 {
  name: 'Blessing Ogabere',
  nationality: 'Nigerian',
  age: 26,
  height: '78ft'
 },
  {
  name: 'Usain Bolt',
  nationality: 'Jamican',
  age: 29,
  height: '82ft'
 },
{
  name: 'Fred KERLEY',
  nationality: 'USA',
  age: 16,
  height: '82ft'
 },
{
  name: 'Oblique SEVILLE',
  nationality: 'Jamican',
  age: 17,
  height: '82ft'
 },
]

Our array of athletes comprises an object for each athlete, each with a name, nationality, age, and height. In order to qualify for an athletic competition, age is the most common attribute, so we will use this to group the data:

const eligible  = {eligible: true };
const ineligible = {ineligible: true };

ATHLETES.groupByToMap((athlete, index, array) => {
  return athlete.age > 18 ? eligible: ineligible;
});

// results: 
Map { 
{eligible: true}: [
{
  name: 'Blessing Ogabere',
  nationality: 'Nigerian',
  age: 26,
  height: '78ft'
 },
  {
  name: 'Usain Bolt',
  nationality: 'Jamican',
  age: 29,
  height: '82ft'
 }
],
 {ineligible: true}: [
{
  name: 'Fred KERLEY',
  nationality: 'USA',
  age: 16,
  height: '82ft'
 },
{
  name: 'Oblique SEVILLE',
  nationality: 'Jamican',
  age: 17,
  height: '82ft'
 }
] 
}

The code below uses groupToMap() with an arrow function that returns the object keys named eligible or ineligible, depending on whether the element has an age greater than 18. The returned result object is a Map.

In order to obtain an array from a Map we need to call get() with the key to obtain the array:

const results = ATHLETES.groupByToMap((athlete) => {
  return athlete.age > 18 ? eligible: ineligible;
});

console.log(results.get(eligible));

//result:
[
{
  name: 'Blessing Ogabere',
  nationality: 'Nigerian',
  age: 26,
  height: '78ft'
 },
  {
  name: 'Usain Bolt',
  nationality: 'Jamican',
  age: 29,
  height: '82ft'
 }
]

Here is the groupToMap method being used in a React project:

Array GroupToMap Map Method

Array GroupToMap Map Method by bonarhyme using core-js, react, react-dom, react-scripts




Differences between the group and groupToMap methods

Group GroupToMap
This returns a new object where each key is the different keys you sorted with This returns a Map with the unique values from the callback function as keys, which can be used to access the array of elements in each group
The results returned can be accessed using the different values that have now been set as keys, just like in a regular object The results returned can be accessed using the get method available in Maps
The values of the key specified for the sorting are used to group the array The custom value you have created is used to group the array
This does not require a conditional to sort the array This requires a conditional to group the array

Alternatives to group

Using Lodash

Lodash is the most well-known utility library for JavaScript and was created to tackle many of the missing APIs that did not exist in older versions of JavaScript.

While many APIs now exist, people still use Lodash when building applications. Lodash has a groupBy function 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:

import groupBy from 'lodash.groupby';

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

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

Using Ramda

Ramda 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:

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:

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

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

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 dog’s name, group them, and make this a reusable function.

Create your own group

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

Because the group function is not currently in the core language; you can create your own group function to use until the official version is released. Let’s look at how we could create our version:

const group = (list, key) => {
    return list.reduce((prev, curr) => {
        return {
            ...prev,
            [curr[key]]: [
                ...(prev[key] || []),
                curr, 
            ]
        }    
    }, {})
}
group(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 function to do our grouping.

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

The most efficient way to group an array

At the time of writing, the most efficient way to actually group an array is using theArray.reduce method. This method was used in the example in the create your own group section of this article. However, using the group and groupToMap array method means we are actually using a method that has been vetted to work well.

Conclusion

The addition of group and groupToMap is a small change to the language. Still, 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.

: 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 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 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!

.
Chris Laughlin JavaScript nerd with 10 plus years of experience in web development. I like tech, coffee and photography. I can usually be found at my desk in the dark making the world a better place, one arrow function at a time.

2 Replies to “Understanding JavaScript’s Array.Group and Array.GroupToMap”

  1. For the Ramda example you ought to just prop(‘breed’) as in groupBy(prop(‘breed’), DOGS). Otherwise exciting new feature.

  2. Correction for the javascript version:

    [curr[key]]: [
    …(prev[curr[key]] || []),
    curr,
    ]

Leave a Reply