Reputation: 383
How to get from this array
[
{name: "a", weight: 1},
{name: "b", weight: 3},
{name: "a", weight: 5},
{name: "b", weight: 7}
]
get this array(weight of duplicates summed)
[
{name: "a", weight: 6},
{name: "b", weight: 10}
]
Upvotes: 1
Views: 560
Reputation: 434685
You don't need any fancy Underscore stuff for this, you can do it all with a single reduce
call:
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: { } });
Then your array will be in result.a
.
Demo: http://jsfiddle.net/ambiguous/6UaXr/
If you must, you can use _.reduce
instead of the native reduce
.
There are a couple tricks here:
reduce
memo caches the results by name in an object and in an array at the same time. Indexing by in m.by_name
gives you quick lookups but you want an array as the final result so we build that along the way too.m.by_name[e.name]
also updates the array.by_name
entries are created (and the references carefully shared) the first time we need them. We also initialize the cached weights with zero so that all the summarizing is done in a single m.by_name[e.name].weight += e.weight
.Upvotes: 1
Reputation: 276306
Something like this should work using groupBy
reduce
and pluck
:
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
Note that we are reduce
ing using native JavaScript reduce, if you want Underscore's reduce you need to chain inside before the _.pluck
, call .reduce
and then call .value
.
Upvotes: 1