如何通过将第二个值与lodash / underscore相加来减少非唯一元素的数组?

时间:2014-06-09 22:34:04

标签: arrays underscore.js lodash

如何从这个数组中获取

[
    {name: "a", weight: 1}, 
    {name: "b", weight: 3}, 
    {name: "a", weight: 5},
    {name: "b", weight: 7}
]

得到这个数组(重复的重量总和)

[
    {name: "a", weight: 6}, 
    {name: "b", weight: 10}
]

2 个答案:

答案 0 :(得分:1)

这样的事情应该可以使用groupBy reducepluck

var sum = function(a,b){ return a+b; };

_.chain([
    {name: "a", weight: 1}, 
    {name: "b", weight: 3}, 
    {name: "a", weight: 5},
    {name: "b", weight: 7}
]).groupBy('name') // we first group them by name
.map(function(v){  // them we map group to the name, and the sum of weights
      return {name:v[0].name,weight:_.pluck(v,"weight").reduce(sum)};
}).value(); // finally, we get the value

请注意,我们reduce使用原生JavaScript减少,如果您希望减少Underscore,则需要在_.pluck之前进行链接,调用.reduce,然后调用.value

答案 1 :(得分:1)

你不需要任何花哨的下划线东西,你可以通过一次reduce电话来完成所有这些:

var result = a.reduce(function(m, e) {
    if(!m.by_name[e.name]) {
        m.by_name[e.name] = { name: e.name, weight: 0 };
        m.a.push(m.by_name[e.name]);
    }
    m.by_name[e.name].weight += e.weight;
    return m;
}, { a: [ ], by_name: { } });

然后你的数组将在result.a

演示:http://jsfiddle.net/ambiguous/6UaXr/

如果必须,您可以使用_.reduce代替原生reduce

这里有一些技巧:

  1. reduce备忘录同时按名称在对象和数组中缓存结果。在m.by_name中编制索引可以快速查找,但是你想要一个数组作为最终结果,所以我们也一直在构建它。
  2. by-name对象和数组共享相同的引用,因此递增m.by_name[e.name]也会更新数组。
  3. 我们第一次需要时创建by_name个条目(以及仔细分享的引用)。我们还将缓存的权重初始化为零,以便所有摘要都在一个m.by_name[e.name].weight += e.weight中完成。