using lodash .groupBy. how to add your own keys for grouped output?
Solution 1
You can do it like this in both Underscore and Lodash (3.x and 4.x).
var data = [{
"name": "jim",
"color": "blue",
"age": "22"
}, {
"name": "Sam",
"color": "blue",
"age": "33"
}, {
"name": "eddie",
"color": "green",
"age": "77"
}];
console.log(
_.chain(data)
// Group the elements of Array based on `color` property
.groupBy("color")
// `key` is group's name (color), `value` is the array of objects
.map((value, key) => ({ color: key, users: value }))
.value()
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>
Original Answer
var result = _.chain(data)
.groupBy("color")
.pairs()
.map(function(currentItem) {
return _.object(_.zip(["color", "users"], currentItem));
})
.value();
console.log(result);
Note: Lodash 4.0 onwards, the .pairs
function has been renamed to _.toPairs()
Solution 2
Isn't it this simple?
var result = _(data)
.groupBy(x => x.color)
.map((value, key) => ({color: key, users: value}))
.value();
Solution 3
Highest voted answer uses Lodash _.chain
function which is considered a bad practice now "Why using _.chain
is a mistake."
Here is a fewliner that approaches the problem from functional programming perspective:
import tap from "lodash/fp/tap";
import flow from "lodash/fp/flow";
import groupBy from "lodash/fp/groupBy";
const map = require('lodash/fp/map').convert({ 'cap': false });
const result = flow(
groupBy('color'),
map((users, color) => ({color, users})),
tap(console.log)
)(input)
Where input
is an array that you want to convert.
Solution 4
another way
_.chain(data)
.groupBy('color')
.map((users, color) => ({ users, color }))
.value();
Solution 5
Thanks @thefourtheye, your code greatly helped. I created a generic function from your solution using the version 4.5.0 of Lodash.
function groupBy(dataToGroupOn, fieldNameToGroupOn, fieldNameForGroupName, fieldNameForChildren) {
var result = _.chain(dataToGroupOn)
.groupBy(fieldNameToGroupOn)
.toPairs()
.map(function (currentItem) {
return _.zipObject([fieldNameForGroupName, fieldNameForChildren], currentItem);
})
.value();
return result;
}
To use it:
var result = groupBy(data, 'color', 'colorId', 'users');
Here is the updated fiddler;
user1767105
Updated on January 08, 2022Comments
-
user1767105 over 2 years
I have this sample data returned from an API.
I'm using Lodash's
_.groupBy
to convert the data into an object I can use better. The raw data returned is this:[ { "name": "jim", "color": "blue", "age": "22" }, { "name": "Sam", "color": "blue", "age": "33" }, { "name": "eddie", "color": "green", "age": "77" } ]
I want the
_.groupBy
function to return an object that looks like this:[ { color: "blue", users: [ { "name": "jim", "color": "blue", "age": "22" }, { "name": "Sam", "color": "blue", "age": "33" } ] }, { color: "green", users: [ { "name": "eddie", "color": "green", "age": "77" } ] } ]
Currently I'm using
_.groupBy(a, function(b) { return b.color})
which is returning this.
{blue: [{..}], green: [{...}]}
the groupings are correct, but I'd really like to add the keys I want (
color
,users
). is this possible using_.groupBy
? or some otherLoDash
utility? -
Benny Bottema almost 9 yearsVery nifty, but hard to wrap my head around. Can you explain the steps in between, especially the pairing and zipping (and the double zip, since
_.object
is an alias for_.zipObject
). -
thefourtheye almost 9 yearsPrint the result after each step. It might help you understand better. If you have specific question please let me know. I'll help you with that
-
Benny Bottema almost 9 yearslodash 3.10.0 and some logging for every step: jsfiddle.net/plantface/WYCF8/171. It's still a puzzle, but I'm getting there. Haven't used
_.zip
and_.pair
so much yet. -
Erik Schierboom over 8 yearsIn lodash 4.x, the
pairs()
method does not exist anymore. An updated lodash 4.0 version of this example is:.chain(data).groupBy('color') .toPairs().map(function (pair) { return _.zipObject(['Name', 'Suppliers'], air); }).value();
-
Adam Klein over 8 yearsI feel like loadash should have a function that does this very exact thing. I would think users would want to group an array of objects by a property all the time.
-
Pikachu-go over 7 yearsI am getting Object instead of values [ { color: '0', users: [ [Object], [Object] ] } May be a newbie issue - help is greatly appreciated.
-
Martin Magakian over 7 yearsSimilar to @thefourtheye's answer but a bit easier to understand
-
Jeremy A. West about 7 yearsThis seems much cleaner to me, and appears to be returning the same results. Thanks!
-
Ben Cochrane over 6 yearsThe updated version to this answer which worked well is:
var result = lodash.chain(res) .groupBy('color') .toPairs() .map(function(currentItem) { return lodash.zipObject(['color', 'users'], currentItem) }) .value();
-
Pawel over 6 yearsUsing
_.chain
is considered a bad practice now. -
Wei-jye almost 6 yearswow. what syntax is this? First time seeing that you can pass the array into the constructor
-
B Medeiros over 4 yearsI tried to use
flow()
instead ofchain()
here, but typescript's type checking simply go crazy with composed functions. I hope we have the same level of support we currently have in RxJS'spipe()
, for example, in lodash. -
Gil Epshtain about 4 yearsI really like your map() syntax, very cool
map((users, color) => ({color, users}))
instead ofmap((value, key) => ({ color: key, users: value }))
-
Julian about 3 yearsThe problem of preventing treeshaking only applies to Lodash. In Underscore, you can customize which functions get mixed into
_
since version 1.11. -
Mo. over 2 years@ErikSchierboom what is air? You mean
pair
!