phileras phileras - 3 months ago 11
JSON Question

How to reduce an array of objects and avoid to overwrite string properties values and just sum integers values?

I have an array grouped by different categories and each category have nested more objects with different values (numeric and strings) which i have to reduce (except the strings). Reduce is working fine with numeric values making a sum of them but its overwriting the string values keeping just the last one.

I'm trying to reduce an object/dictionnary by category and fill a table with the sum of the units of each category but don't sum them if the subcategories and names are different.

Here is a demo:



var data = {
'Category xxxx': [
{
units: 1234,
subcategory: 'wolves',
name: 'Starks'
},
{
units: 1345354,
subcategory: 'wolves',
name: 'Starks'
},
{
units: 666,
subcategory: 'dragons',
name: 'Targaryens'
}
],
'Category yyyy': [
{
units: 7783,
subcategory: 'lions',
name: 'Lanisters'
},
{
units: 1267878,
subcategory: 'spires',
name: 'Martells'
}
]
}

var test = _.map(data, function (value, key) {
var returnedData = {
Category: key,
units: _(value).reduce(function (memo, metrics) {
return memo + metrics.units;
}, 0),
subcategory: _(value).reduce(function (memo, metrics) {
return metrics.subcategory;
}, 0),
name: _(value).reduce(function (memo, metrics) {
return metrics.name;
}, 0),
};
return returnedData;
});

console.log(test)

<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>





The units (integers) are adding up fine but the strings get overwritten by the last iterated string property.

I want to obtain something like this where if the strings are different the integers are not added up.

returnedData = {
'Category xxxx': [
{
units: 1346588,
chivalry: 'wolves',
name: 'Starks'
},
{
units: 666,
subcategory: 'dragons',
name: 'Targaryens'
}
],
'Category yyyy': [
{
clicks: 7783,
subcategory: 'lions',
name: 'Lanisters'
},
{
clicks: 1267878,
subcategory: 'spires',
name: 'Martells'
}
]
}


What is the best way to do it?

Answer

Finally, this proposal uses an object as reference to the items of the result object.

If no result object is available, then it creates a new one with the wanted category. For subcategories it generates an element which is pushed to the result array.

The count is maintained with hash as reference to the elements of result.

var data = { 'Category xxxx': [{ clicks: 1234, subcategory: 'dogs', name: 'jhon doe' }, { clicks: 1345354, subcategory: 'dogs', name: 'jhon doe' }], 'Category yyyy': [{ clicks: 7783, subcategory: 'frogs', name: 'lanisters' }, { clicks: 1267878, subcategory: 'rats', name: 'perry' }] },
    result = {};

Object.keys(data).forEach(function (k) {
    var hash = Object.create(null);
    if (!result[k]) {
        result[k] = [];
    }
    data[k].forEach(function (a) {
        if (!hash[a.subcategory]) {
            hash[a.subcategory] = { clicks: 0, subcategory: a.subcategory, name: a.name };
            result[k].push(hash[a.subcategory]);
        }
        hash[a.subcategory].clicks += a.clicks;
    });
});

console.log(result);