Reduce an array of objects by key and amount into an array

I have the following object:

data = [ { name: 'foo', type: 'fizz', val: 9 }, { name: 'foo', type: 'buzz', val: 3 }, { name: 'bar', type: 'fizz', val: 4 }, { name: 'bar', type: 'buzz', val: 7 }, ]; 

And the lodash card used:

 result = _.map(data, function item, idx){ return { key: item[key], values: item.value, } } 

Result:

 [ { key: foo, val: 9 }, { key: foo, val: 3 }, { key: bar, val: 4 }, { key: bar, val: 7 }, ] 

but now I'm trying to return:

 [ { key: 'foo', val: 12 }, { key: 'bar', val: 11 }, ] 

I tried using a shorthand that seems to only output one object, which I could then convert back to an array, but I feel that there should be an elegant way to use lodash to go from my source data directly to my desired result without any intermediate steps .

I thought this one was affecting my exact problem, but there seems to be quite a bit of work just to convert the object to the desired array of objects described above.

Greetings.

+5
source share
3 answers

Interestingly, not directly, because of the need to accumulate the value by the key, and then want the key as the value of the property key. The reverse map seems to reduce:

 var result = _.chain(data) .reduce(function(memo, obj) { if(typeof memo[obj.name] === 'undefined') { memo[obj.name] = 0; } memo[obj.name] += obj.val; return memo; }, {}) .map(function (val, key) { return {key: key, val: val}; }) .value(); 

For brevity in es6:

 _.chain(data) .reduce((memo, obj) => { memo[obj.name = obj.val] += obj.val; return memo; }, {}) .map((val, key) => ({key, val})) .value(); 
+4
source

Acknowledgment of the accepted answer that uses groupBy instead of abbreviation to make the initial grouping:

 var result = _.chain(data) .groupBy('name') .map((group, key) => ({ key, val : _.sumBy(group, 'val') })) .value(); 
+5
source

You can get all the unique names with map () and uniq () , and then map () with each name to get its corresponding amounts using sumBy () .

 var result = _(data) .map('name') .uniq() .map(key => ({ key, val: _(data).filter({ name: key }).sumBy('val') })) .value(); 

 var data = [ { name: 'foo', type: 'fizz', val: 9 }, { name: 'foo', type: 'buzz', val: 3 }, { name: 'bar', type: 'fizz', val: 4 }, { name: 'bar', type: 'buzz', val: 7 } ]; var result = _(data) .map('name') .uniq() .map(key => ({ key, val: _(data).filter({ name: key }).sumBy('val') })) .value(); console.log(result); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.13.1/lodash.js"></script> 

Here is the non es6 version:

 var result = _(data) .map('name') .uniq() .map(function(key) { return { key: key, val: _(data).filter({ name: key }).sumBy('val') }; }) .value(); 
+1
source

All Articles