Skip to content Skip to sidebar Skip to footer

Sum Similar Keys In An Array Of Objects In Javascript

I have an array of objects something like the following: - 0: {Id: 0, count1: 5, count2: 10, yearMonth: '201803'} 1: {Id: 0, count1: 10, count2: 0, yearMonth: '201804'} 2: {Id: 1,

Solution 1:

With knockout, you can use a chain of computed properties to get to the desired (UI?) format!

Disclaimer: I'm assuming this list will not contain thousands of items

1. Grouping

The first step is to go from a list (ko.observableArray([])) of items to a computed object that groups by id:

// Search for "group by javascript" to have this function explainedconstgroupBy = (prop, xs) => xs.reduce(
  (acc, x) =>Object.assign(acc, { [x[prop]]: (acc[x[prop]] || []).concat(x) }), {}
);

const items = ko.observableArray([]);

const itemsById = ko.pureComputed(() =>groupBy("Id", items())
);

itemsById.subscribe(console.log);
items([{Id: 0, count1: 5, count2: 10, yearMonth: "201803"},{Id: 0, count1: 10, count2: 0, yearMonth: "201804"},{Id: 1, count1: 900, count2: 200, yearMonth: "201805"},{Id: 0, count1: 10, count2: 0, yearMonth: "201806"},{Id: 1, count1: 100, count2: 100, yearMonth: "201807"},{Id: 1, count1: 100, count2: 2, yearMonth: "201808"}]);
<scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

2. Merging

Now that we have grouped lists of items that need to be summarized, we can start applying our merge logic:

const itemsWithSameId = [{Id:0,count1:5,count2:10,yearMonth:"201803"},{Id:0,count1:10,count2:0,yearMonth:"201804"},{Id:0,count1:10,count2:0,yearMonth:"201806"}];

constmerge = (itemA, itemB) => ({
  Id: itemB.Id,
  count1: itemA.count1 + itemB.count1,
  count2: itemA.count2 + itemB.count2
});

// Look up "merging objects using reduce in javascript" to find out moreconsole.log(
  itemsWithSameId.reduce(merge, { count1: 0, count2: 0 })
)

3. Going back from indexed object to array

Now that we know how to merge our groups, we can move back to the array we need in our UI:

// Utilities:constgroupBy = (prop, xs) => xs.reduce(
  (acc, x) =>Object.assign(acc, {
    [x[prop]]: (acc[x[prop]] || []).concat(x)
  }), {}
);

// Data Logic:constmerge = (itemA, itemB) => ({
  Id: itemB.Id,
  count1: itemA.count1 + itemB.count1,
  count2: itemA.count2 + itemB.count2
});

// Appconst items = ko.observableArray([]);
const itemsById = ko.pureComputed(() =>groupBy("Id", items())
);

// Look up "mapping over the values of a javascript object" for more infoconst summedItems = ko.pureComputed(() =>Object
    .values(itemsById())
    .map(items => items.reduce(merge, { count1: 0, count2: 0 }))
);

// Apply bindings with viewmodel exposing summedItems
ko.applyBindings({ summedItems });

// Inject data (probably in success callback of ajax call)items([{Id: 0, count1: 5, count2: 10, yearMonth: "201803"},{Id: 0, count1: 10, count2: 0, yearMonth: "201804"},{Id: 1, count1: 900, count2: 200, yearMonth: "201805"},{Id: 0, count1: 10, count2: 0, yearMonth: "201806"},{Id: 1, count1: 100, count2: 100, yearMonth: "201807"},{Id: 1, count1: 100, count2: 2, yearMonth: "201808"}]);
<scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script><table><thead><tr><th>Id</th><th>Count 1</th><th>Count 2</th></tr></thead><tbodydata-bind="foreach: summedItems"><tddata-bind="text: Id"></td><tddata-bind="text: count1"></td><tddata-bind="text: count2"></td></tbody></table>

Solution 2:

You could reduce the array by using a hash table and an array of keys for summing the wanted values.

var data = [{ Id: 0, count1: 5, count2: 10, yearMonth: "201803" }, { Id: 0, count1: 10, count2: 0, yearMonth: "201804" }, { Id: 1, count1: 900, count2: 200, yearMonth: "201805" }, { Id: 0, count1: 10, count2: 0, yearMonth: "201806" }, { Id: 1, count1: 100, count2: 100, yearMonth: "201807" }, { Id: 1, count1: 100, count2: 2, yearMonth: "201808" }],
    keys = ['count1', 'count2'],
    grouped = Object.values(data.reduce((result, object) => {
        result[object.Id] = result[object.Id] || { Id: object.Id };
        keys.forEach(key => result[object.Id][key] = (result[object.Id][key] || 0) + object[key]);
        return result;
    }, Object.create(null)));

console.log(grouped);
.as-console-wrapper { max-height: 100%!important; top: 0; }

Post a Comment for "Sum Similar Keys In An Array Of Objects In Javascript"