In this article i’ll walk you through how I converted lodash’s built in groupBy
function to plain JavaScript.
TL;DR Here’s the code I came up with to convert the lodash groupBy function
const groupBy = (array, groupByKey) => {
const uniqueKeys = [...new Set(array.map(item => item[groupByKey]))];
const groupItems = uniqueKeys.map(key =>
({ [key]: array.filter(item => item[groupByKey] === key)}));
};
So i’ve been working on an AngularJS migration at work and there’s a lot of dependency on the lodash
library to do things like get nested properties, map and reduce arrays etc.
Which is fine, as lodash is very helpful at doing these kinds of things however there are a lot of these functions that are available natively in JavaScript now (map, reduce, filter etc.) so why not use them?
Plus, we found there was a reasonable performance bottleneck when using some of the functions and converting them to plain JavaScript gave us a much more performant app which is important as a lot of our end users will be on low-spec machines.
What is groupBy?
Anyway, one function which I came across is the lodash groupBy
function which (amongst other things) can pick out a common property from an array of objects and return an object with the unique values of the common properties as keys with the values set as the array items that match that particular ‘picked out’ key.
Confused?
Let’s look at an example.
So imagine an array like this:
var cars = [
{
make: 'audi',
model: 'r8',
year: '2012'
},
{
make: 'audi',
model: 'rs5',
year: '2013'
},
{
make: 'ford',
model: 'mustang',
year: '2012'
},
{
make: 'ford',
model: 'fusion',
year: '2015'
},
{
make: 'kia',
model: 'optima',
year: '2012'
},
];
And we want to convert this to a grouped object like this:
const cars = {
audi: [
{
model: 'r8',
year: '2012'
},
{
model: 'rs5',
year: '2013'
},
],
ford: [
{
model: 'mustang',
year: '2012'
},
{
model: 'fusion',
year: '2015'
}
],
kia: [
{
model: 'optima',
year: '2012'
}
]
}
Data courtesy of this SO question: https://stackoverflow.com/questions/40774697/how-to-group-an-array-of-objects-by-key
Pretty handy right?
The trouble is there are several steps to this process so it’s not just as simple as using a single map
function for example.
Here’s how I approached it.
Converting lodash groupBy
Breaking down the problem I realised:
- We need to get a list of unique values for a particular key name
- We need to return a new object with those values as keys
- The value of each key in the new object needs to have the items in the original array that match that particular key value
So using the above car data example, step by step that gives us:
Create a new array which has the unique keys.
const groupBy = 'make';
const uniqueKeys = [...new Set(cars.map(car => car[groupBy]))];
Return a new Object
const groupItems = uniqueKeys.map(key => ({ [key]: })); // TBC
Populate the object with the items in the array that match the key
const groupItems = uniqueKeys.map(key =>
({ [key]: cars.filter(car => car[groupBy] === key)}));
Obviously you can change the value stored in cars to any array and use a different groupBy
value to pick out any particular property from the objects in the array.
Foolproof solution?
There are probably a few issues with this as I don’t know how lodash handles nested arrays for this particular method and we’re obviously relying on the property to exist for each object in the array.
But this seems to do the trick if you want to quickly move away from the lodash groupBy
function or you don’t want to have to import the whole library just for this one function.