Given the following array of objects:
myArray = [
{
item: 'Item 1',
material: 'Material1',
type: 'head'
},
{
item: 'Item 1',
material: 'Material1',
type: 'head'
},
{
item: 'Item 2',
material: 'Material2',
type: 'shell'
},
{
item: 'Item 1',
material: 'Material1',
type: 'head'
},
{
item: 'Item 2',
material: 'Material2',
type: 'shell'
},
{
item: 'Item 3',
material: 'Material3',
type: 'support'
},
{
item: 'Item 1',
material: 'Material1',
type: 'head'
},
{
item: 'Item 3',
material: 'Material3',
type: 'support'
},
{
item: 'Item 2',
material: 'Material2',
type: 'shell'
}
]
I need to bine these by the item
value with a count so that I get an array that looks like this:
var myResultArray = [
{
item: 'Item 1',
material: 'Material1',
type: 'head'
count: 4
},
{
item: 'Item 2',
material: 'Material2',
type: 'shell'
count: 3
},
{
item: 'Item 3',
material: 'Material3',
type: 'support'
count: 2
},
]
What is the easiest way to do this? I'm partial to Lodash, but I'm open to other alternatives. With _.groupBy()
I can get everything grouped together with the item as the object key:
var myGrouped = _.groupBy(myArray, 'item');
but that only gets me part way there. Searching around here I see a lot of uses of _.reduce()
(or just plain .reduce()
) or _.map()
, but I haven't been able to get my head around exactly how to use them in this case. If I try to use _.groupBy()
chained with _.map()
like so
var myGrouped = _(myArray).groupBy('item').map(function(item) {
// do stuff here
});
the execution doesn't even get to my map function, so I'm not sure what I'm doing wrong.
Thanks.
Given the following array of objects:
myArray = [
{
item: 'Item 1',
material: 'Material1',
type: 'head'
},
{
item: 'Item 1',
material: 'Material1',
type: 'head'
},
{
item: 'Item 2',
material: 'Material2',
type: 'shell'
},
{
item: 'Item 1',
material: 'Material1',
type: 'head'
},
{
item: 'Item 2',
material: 'Material2',
type: 'shell'
},
{
item: 'Item 3',
material: 'Material3',
type: 'support'
},
{
item: 'Item 1',
material: 'Material1',
type: 'head'
},
{
item: 'Item 3',
material: 'Material3',
type: 'support'
},
{
item: 'Item 2',
material: 'Material2',
type: 'shell'
}
]
I need to bine these by the item
value with a count so that I get an array that looks like this:
var myResultArray = [
{
item: 'Item 1',
material: 'Material1',
type: 'head'
count: 4
},
{
item: 'Item 2',
material: 'Material2',
type: 'shell'
count: 3
},
{
item: 'Item 3',
material: 'Material3',
type: 'support'
count: 2
},
]
What is the easiest way to do this? I'm partial to Lodash, but I'm open to other alternatives. With _.groupBy()
I can get everything grouped together with the item as the object key:
var myGrouped = _.groupBy(myArray, 'item');
but that only gets me part way there. Searching around here I see a lot of uses of _.reduce()
(or just plain .reduce()
) or _.map()
, but I haven't been able to get my head around exactly how to use them in this case. If I try to use _.groupBy()
chained with _.map()
like so
var myGrouped = _(myArray).groupBy('item').map(function(item) {
// do stuff here
});
the execution doesn't even get to my map function, so I'm not sure what I'm doing wrong.
Thanks.
Share Improve this question asked May 2, 2017 at 0:22 wonder95wonder95 4,3158 gold badges50 silver badges82 bronze badges 2-
1
_.groupBy
followed by_.map
is the correct solution. Can you explain what you mean by "doesn't even get to my map function"? It works in this answer, this answer, and this answer. – castletheperson Commented May 2, 2017 at 0:26 - @4castle I just mean that when I put a breakpoint inside the map() function in my debugger, it didn't stop there. I know it works, so I was assuming I was doing something wrong. – wonder95 Commented May 2, 2017 at 0:56
4 Answers
Reset to default 5_.groupBy
chained with _.map
is the simplest solution. A proper callback function for the _.map
would be:
function (items) {
items[0].count = items.length;
return items[0];
}
Or you could condense it further with ES6 arrow-functions.
const myArray = [{"item":"Item 1","material":"Material1","type":"head"},{"item":"Item 1","material":"Material1","type":"head"},{"item":"Item 2","material":"Material2","type":"shell"},{"item":"Item 1","material":"Material1","type":"head"},{"item":"Item 2","material":"Material2","type":"shell"},{"item":"Item 3","material":"Material3","type":"support"},{"item":"Item 1","material":"Material1","type":"head"},{"item":"Item 3","material":"Material3","type":"support"},{"item":"Item 2","material":"Material2","type":"shell"}];
const myResultArray =
_(myArray)
.groupBy('item')
.map(items => (items[0].count = items.length, items[0]))
.value();
console.log(myResultArray);
<script src="https://cdn.jsdelivr/lodash/4.13.1/lodash.min.js"></script>
I ended up going with this:
var groupedData = [];
_(typeData).groupBy('item').forEach(function(value, key) {
var obj = {};
obj.count = value.length;
obj.type = value[0].type;
obj.details = value[0].details;
obj.description = key;
groupedData.push(obj);
});
If you want to do it without using Lodash, this would create the required array:
const res = myArray.reduce((accum, val) => {
let summary = accum.get(val.item) || Object.assign({}, val, {count:0});
summary.count++;
return accum.set(val.item, summary);
}, new Map());
console.log([...res.values()]);
using _.countBy
and _.uniqBy
var res = _.chain(myArray)
.countBy('item') // get each item count
.thru(counts => // counts = {Item 1: 4, Item 2: 3, Item 3: 2}
_.chain(myArray)
.uniqBy('item') // get uniq items
.map(item => // set each item count
_.assign(
item,
{count: counts[item.item]}
);
)
.value();
)
.value();