Problem
You have an array of objects and want to group them by a certain property.
Ingredients
- the
reduce()
method
Directions
-
Given: an array of objects (e.g.,
persons
) …let persons = [ { firstName: 'John', lastName: 'Doe' }, { firstName: 'Jane', lastName: 'Doe' }, { firstName: 'Jane', lastName: 'Smith' }, { firstName: 'Dave', lastName: 'Smith' }, { firstName: 'Jane', lastName: 'Carpenter' } ]
-
… and you want to group those objects by a property (e.g., by
firstName
).let groupedByFirstName = groupBy(persons, 'firstName'); console.log(groupedByFirstName); // should look like this: /* { "John": [ { "firstName": "John", "lastName": "Doe" } ], "Jane": [ { "firstName": "Jane", "lastName": "Doe" }, { "firstName": "Jane", "lastName": "Smith" }, { "firstName": "Jane", "lastName": "Carpenter" } ], "Dave": [ { "firstName": "Dave", "lastName": "Smith" } ] } */
-
Create a function named
groupBy()
that accepts an array and the name of a property (we will use the arrow function style for defining that function).const groupBy = (array, property) => {}
-
Call the
reduce()
method on the array of objects and pass in an empty object as second parameter ({}
). This object will be the result object containing the grouped objects of the array.const groupBy = (array, property) => array.reduce((grouped, object) => { ... }, {});
-
In the callback function of the
reduce()
method for every object get the value of the given property.const groupBy = (array, property) => array.reduce((grouped, object) => { let value = object[property]; ... }, {});
-
Initialize the array for that value in the result object (
grouped
) if it wasn’t initialized yet …const groupBy = (array, property) => array.reduce((grouped, object) => { let value = object[property]; if(!grouped[value]) { grouped[value] = []; } ... }, {});
-
… which can also be written like this:
const groupBy = (array, property) => array.reduce((grouped, object) => { let value = object[property]; grouped[value] = grouped[value] || []; ... }, {});
-
Push the current object to that array.
const groupBy = (array, property) => array.reduce((grouped, object) => { let value = object[property]; grouped[value] = grouped[value] || []; grouped[value].push(object); ... }, {});
-
… and return the result object.
const groupBy = (array, property) => array.reduce((grouped, object) => { let value = object[property]; grouped[value] = grouped[value] || []; grouped[value].push(object); return grouped; }, {});
-
Voilá, a tasteful helper function for grouping objects by property.
const groupBy = (array, property) => array.reduce((grouped, object) => { let value = object[property]; grouped[value] = grouped[value] || []; grouped[value].push(object); return grouped; }, {}); let persons = [ { firstName: 'John', lastName: 'Doe' }, { firstName: 'Jane', lastName: 'Doe' }, { firstName: 'Jane', lastName: 'Smith' }, { firstName: 'Dave', lastName: 'Smith' }, { firstName: 'Jane', lastName: 'Carpenter' } ] let groupedByFirstName = groupBy(persons, 'firstName'); console.log(groupedByFirstName); /* looks like this: { "John": [ { "firstName": "John", "lastName": "Doe" } ], "Jane": [ { "firstName": "Jane", "lastName": "Doe" }, { "firstName": "Jane", "lastName": "Smith" }, { "firstName": "Jane", "lastName": "Carpenter" } ], "Dave": [ { "firstName": "Dave", "lastName": "Smith" } ] } */
Notes
-
The
groupBy()
function shown in this recipe only works for direct properties, not for nested properties. For example in the following code snippet you cannot group the person objects by city using the current implementation ofgroupBy()
.let persons = [ { firstName: 'John', lastName: 'Doe', address: { city: 'London' } }, { firstName: 'Jane', lastName: 'Doe', address: { city: 'Birmingham' } }, { firstName: 'Jane', lastName: 'Smith', address: { city: 'Birmingham' } }, { firstName: 'Dave', lastName: 'Smith', address: { city: 'London' } }, { firstName: 'Jane', lastName: 'Carpenter', address: { city: 'Birmingham' } } ] // this won't work let groupedByCity = groupBy(persons, 'address.city'); console.log(groupedByCity);
Alternative recipes
- Tomorrow we will see how to further improve the
groupBy()
function, so that you can group objects by nested properties as well.