Using Lodash .Groupby. How to Add Your Own Keys for Grouped Output

using lodash .groupBy. how to add your own keys for grouped output?

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>

lodash .groupBy. how to add your own keys for grouped output?

You can first use _.groupBy() to group each object, and then _.map() each group in the object to an array of objects. Each mapped object uses the key from the grouped object as the car_brand, as well as uses a mapped version of the grouped value array as the model property:

const arr = [{ "car_brand": "audi", "model": { "model_1": "audi_tt" } }, { "car_brand": "audi", "model": { "model_1": "audi_r8" } } ];
const group = _.flow( inp => _.groupBy(inp, 'car_brand'), gr => _.map(gr, (arr, card_brand) => ({ card_brand, model: _.map(arr, 'model') })));
console.log(group(arr));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>

groupBy and value as key

You got very close to solving your own question. Well done! Let's break this into parts and see what's missing.

You correctly identified that _.groupBy is what you need in order to collect objects with the same GroupID.

var grouped = _.groupBy(groups, 'GroupID');
// { '1':
// [ { GroupID: 1, AttributeID: 'Agitator', Value: 'No' },
// { GroupID: 1, AttributeID: 'ATG', Value: 'Custodian' },
// { GroupID: 1, AttributeID: 'Heating Coil', Value: 'Mild Steel' } ],
// '2':
// [ { GroupID: 2, AttributeID: 'Agitator', Value: 'Yes' },
// { GroupID: 2, AttributeID: 'ATG', Value: 'Non Custodian' },
// { GroupID: 2, AttributeID: 'Heating Coil', Value: 'Mild Steel' } ] }

You also correctly identified _.map as the function that lets you collect the values of a particular property across an array of objects.

var firstGroupAttributes = _.map(grouped['1'], 'AttributeID');
// [ 'Agitator', 'ATG', 'Heating Coil' ]

The function you wrote to construct the final object for each group produced the following object for the first group:

{
'GroupID': 1,
'AttributeID': ['Agitator', 'ATG', 'Heating Coil'],
'Value': ['No', 'Custodian', 'Mild Steel']
}

Conveniently, the AttributeID and Value properties have the same order, so the first element of the Value array corresponds to the first element of the AttributeID array, the second to the second, and so forth. Underscore has a function called _.object1, which can take such a pair of arrays and return an object where each element of the first array names a property and the corresponding element of the second array provides its value:

_.object(['Agitator', 'ATG'], ['No', 'Custodian']);
// { Agitator: 'No',
// ATG: 'Custodian', }

Having taken care of the attributes and their values, now we just need to add the GroupID to the object. There are several similar but slightly different functions that work for this purpose, such as _.extend and _.defaults:

_.extend({ a: 1 }, { b: 2 });
// { a: 1, b: 2 }

Putting these ingredients together, the function that we map over grouped could look something like this:

function mergeGroup(value, key) {
var attributes = _.map(value, 'AttributeID');
var values = _.map(value, 'Value');
return _.chain(attributes).object(values).extend({ GroupID: key }).value();
}

If you use _.map, as you did, you get an array with the final objects.

var data = _.chain(groups).groupBy('GroupID').map(mergeGroup).value();
// [ { Agitator: 'No',
// ATG: 'Custodian',
// 'Heating Coil': 'Mild Steel',
// GroupID: '1' },
// { Agitator: 'Yes',
// ATG: 'Non Custodian',
// 'Heating Coil': 'Mild Steel',
// GroupID: '2' } ]

Alternatively, you could use _.mapObject2 to produce an object where each key is the same as the GroupID:

var data = _.chain(groups).groupBy('GroupID').mapObject(mergeGroup).value();
// { '1':
// { Agitator: 'No',
// ATG: 'Custodian',
// 'Heating Coil': 'Mild Steel',
// GroupID: '1' },
// '2':
// { Agitator: 'Yes',
// ATG: 'Non Custodian',
// 'Heating Coil': 'Mild Steel',
// GroupID: '2' } }

1 Lodash originally inherited _.object from Underscore, but they added an alias called _.zipObject and in version 4, they decided to remove the original name _.object from their interface. So you'd have to call _.zipObject if using Lodash. Underscore's _.object can also work with an array of pairs instead of a pair of arrays; in Lodash 4, you'd use _.fromPairs for that instead.

2 _.mapValues in Lodash.

how to groupby objects using lodash and map over the list -react

You just need to group by division then map the result to the format you want.

const groups = _(conLocations)
.groupBy('division')
.map((locations, division) => {
const country = locations.map(location => location.country);
return ({
division,
country,
})
})
.value();

Above code will return the result in this format

[  
{
division:'Agricultural',
country:[
'USA',
'CANADA'
]
},
{
division:'Industrial',
country:[
'AUSTRALIA'
]
}
]

lodash groupBy all keys most efficient way

You can use mergeWith() as follows:

const output = _.mergeWith({}, ...input, (t, s) => {
if (!_.isObject(s)) return t ? [...t, s] : [s]
});

const input = [{  food: {    fruits: {      apples: 2,      bananas: 3,      peaches: 'square',      citrus: [100, 200, 300]    },    meat: {      beef: 1000,      chicken: 2000    }  }}, {  food: {    fruits: {      apples: 4,      bananas: 5,      peaches: 'triangle',      citrus: [101, 201, 301]    },    meat: {      beef: 1001,      chicken: 2001    }  }}];
const output = _.mergeWith({}, ...input, (t, s) => { if (!_.isObject(s)) return t ? [...t, s] : [s]});
console.log(output);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>

groupBy but for objects and each key

What you want, is nothing but a simple merge (in lodash) with a callback that handles the concatenation.

Let's have a snippet:

const input = [{a:1,b:2}, {a:11, b:22}, {a: 111}];
const res = _.mergeWith({}, ...input, (s = [], o) => [...s, o]);
console.log(res);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>

How can I group an array of objects by key?

Timo's answer is how I would do it. Simple _.groupBy, and allow some duplications in the objects in the grouped structure.

However the OP also asked for the duplicate make keys to be removed. If you wanted to go all the way:

var grouped = _.mapValues(_.groupBy(cars, 'make'),
clist => clist.map(car => _.omit(car, 'make')));

console.log(grouped);

Yields:

{ audi:
[ { model: 'r8', year: '2012' },
{ model: 'rs5', year: '2013' } ],
ford:
[ { model: 'mustang', year: '2012' },
{ model: 'fusion', year: '2015' } ],
kia:
[ { model: 'optima', year: '2012' } ]
}

If you wanted to do this using Underscore.js, note that its version of _.mapValues is called _.mapObject.

lodash - group and populate arrays

You can use groupBy() to group each item in the collection by birthdate. After grouping the items, you can use map() to iterate each groups and form them into a new format that includes a birthdate and names. To acquire an array of names from the grouped items, you can use the map() function again to return all the name values.

var result = _(source)
.groupBy('birthdate')
.map(function(items, bdate) {
return {
birthdate: bdate,
names: _.map(items, 'name')
};
}).value();

var source = [    { "birthdate": "1993", "name": "Ben" },    { "birthdate": "1994", "name": "John" },    { "birthdate": "1995", "name": "Larry" },    { "birthdate": "1995", "name": "Nicole" },    { "birthdate": "1996", "name": "Jane" },    { "birthdate": "1996", "name": "Janet" },    { "birthdate": "1996", "name": "Dora" },];  var result = _(source)    .groupBy('birthdate')    .map(function(items, bdate) {      return {        birthdate: bdate,        names: _.map(items, 'name')      };    }).value();
document.body.innerHTML = '<pre>' + JSON.stringify(result, 0, 4) + '</pre>';
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>

Using lodash groupby when your key is an array of strings

Basically, unwrap ("linearize") the list and then apply groupBy

result = _(cars)
.flatMap(car => car.year.map(
year => _.assign({}, car, {year})
))
.groupBy('year')
.value()

This keeps the year field though, don't know if this is a problem.



Related Topics



Leave a reply



Submit