最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Merge objects in array by value and get count for each - Stack Overflow

programmeradmin2浏览0评论

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
Add a ment  | 

4 Answers 4

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();
发布评论

评论列表(0)

  1. 暂无评论