Jesse Jesse - 6 months ago 14
JSON Question

Reduce array of objects on key and sum value into 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 used lodash map:

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


Which results in:

[
{ 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 reduce which seems to only output to a single object, which I could then convert back into an array, but I feel like there must be an elegant way to use lodash to go from my source data straight to my desired result without all of the intermediate steps.

I thought this was addressing my exact problem, but it seems like quite a bit of work just to have to convert the object into the desired array of objects outlined above.

Cheers.

Answer

Interestingly not straight forward, because of wanting to accumulate the value by key, but then wanting the key as a value of the property key. So somewhat like an inverse map reduce:

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 = 
    _.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();
console.log('result', result); // [{key: 'foo', val: 12}, {key: 'bar', val: 11}]