This fork of JamieMason's implementation changes the key
parameter to be an array of keys instead of just a single key. This makes it possible to group by multiple properties instead of just one.
const groupBy = keys => array =>
array.reduce((objectsByKeyValue, obj) => {
const value = keys.map(key => obj[key]).join('-');
objectsByKeyValue[value] = (objectsByKeyValue[value] || []).concat(obj);
return objectsByKeyValue;
}, {});
Click to see TypeScript version
/**
* Group array of objects by given keys
* @param keys keys to be grouped by
* @param array objects to be grouped
* @returns an object with objects in `array` grouped by `keys`
* @see <https://gist.github.com/mikaello/06a76bca33e5d79cdd80c162d7774e9c>
*/
const groupBy = <T>(keys: (keyof T)[]) => (array: T[]): Record<string, T[]> =>
array.reduce((objectsByKeyValue, obj) => {
const value = keys.map((key) => obj[key]).join('-');
objectsByKeyValue[value] = (objectsByKeyValue[value] || []).concat(obj);
return objectsByKeyValue;
}, {} as Record<string, T[]>);
const cars = [
{ brand: 'Audi', produced: '2016', color: 'black' },
{ brand: 'Audi', produced: '2017', color: 'white' },
{ brand: 'Ford', produced: '2016', color: 'red' },
{ brand: 'Ford', produced: '2016', color: 'white' },
{ brand: 'Peugot', produced: '2018', color: 'white' }
];
const groupByBrand = groupBy(['brand']);
const groupByColor = groupBy(['color']);
const groupByBrandAndYear = groupBy(['brand', 'produced']);
console.log(
JSON.stringify({
carsByBrand: groupByBrand(cars),
carsByColor: groupByColor(cars),
carsByBrandAndYear: groupByBrandAndYear(cars)
}, null, 2)
);
{
"carsByBrand": {
"Audi": [
{
"brand": "Audi",
"produced": "2016",
"color": "black"
},
{
"brand": "Audi",
"produced": "2017",
"color": "white"
}
],
"Ford": [
{
"brand": "Ford",
"produced": "2016",
"color": "red"
},
{
"brand": "Ford",
"produced": "2016",
"color": "white"
}
],
"Peugot": [
{
"brand": "Peugot",
"produced": "2018",
"color": "white"
}
]
},
"carsByColor": {
"black": [
{
"brand": "Audi",
"produced": "2016",
"color": "black"
}
],
"white": [
{
"brand": "Audi",
"produced": "2017",
"color": "white"
},
{
"brand": "Ford",
"produced": "2016",
"color": "white"
},
{
"brand": "Peugot",
"produced": "2018",
"color": "white"
}
],
"red": [
{
"brand": "Ford",
"produced": "2016",
"color": "red"
}
]
},
"carsByBrandAndYear": {
"Audi-2016": [
{
"brand": "Audi",
"produced": "2016",
"color": "black"
}
],
"Audi-2017": [
{
"brand": "Audi",
"produced": "2017",
"color": "white"
}
],
"Ford-2016": [
{
"brand": "Ford",
"produced": "2016",
"color": "red"
},
{
"brand": "Ford",
"produced": "2016",
"color": "white"
}
],
"Peugot-2018": [
{
"brand": "Peugot",
"produced": "2018",
"color": "white"
}
]
}
}
See playcode.io for example.
@mikaello thanks for this, its really helpful!! Would it be possible to group nested values within an array?
For example if we had
Can we group by drivers.email? So result would that Lewis.Hamilton is associated with 4 cars?
eg: