Reputation: 3347
Is there a proper way to merge 2 arrays which are consist of the objects with the same (though not exactly) keys and corresponding numeric values?
As the result i need an array with the sum of objects where the values for the same keys are combined.
Keys are dates (Date()
). each date have corresponding number.
Example:
const series_0 = [
{
'value': 3000,
'name': '2016-09-20T20:23:48.426Z'
},
{
'value': 6000,
'name': '2016-09-21T08:58:04.100Z'
},
{
'value': 4000,
'name': '2016-09-21T05:21:08.317Z'
},
{
'value': 6000,
'name': '2016-09-19T11:26:36.302Z'
},
{
'value': 5000,
'name': '2016-09-16T11:26:19.165Z'
}
]
const series_1 = [
{
'value': 3000,
'name': '2016-09-20T20:23:48.426Z'
},
{
'value': 1500,
'name': '2016-09-21T08:58:04.100Z'
},
{
'value': 8000,
'name': '2016-09-19T11:26:36.302Z'
},
]
desired result:
let result = [
{
'value': 6000,
'name': '2016-09-20T20:23:48.426Z'
},
{
'value': 7500,
'name': '2016-09-21T08:58:04.100Z'
},
{
'value': 4000,
'name': '2016-09-21T05:21:08.317Z'
},
{
'value': 6000,
'name': '2016-09-19T11:26:36.302Z'
},
{
'value': 13000,
'name': '2016-09-16T11:26:19.165Z'
}
]
Thank you!
Upvotes: 0
Views: 3911
Reputation: 92440
I think I would just make a Map object and push add the dates onto it as keys summing as I go along:
const series_0 = [{'value': 3000,'name': '2016-09-20T20:23:48.426Z'},{'value': 6000,'name': '2016-09-21T08:58:04.100Z'},{'value': 4000,'name': '2016-09-21T05:21:08.317Z'},{'value': 6000,'name': '2016-09-19T11:26:36.302Z'},{'value': 5000,'name': '2016-09-16T11:26:19.165Z'}]
const series_1 = [{'value': 3000,'name': '2016-09-20T20:23:48.426Z'},{'value': 1500,'name': '2016-09-21T08:58:04.100Z'},{'value': 8000,'name': '2016-09-19T11:26:36.302Z'},]
let result = [series_0, series_1].reduce((sums, series) =>
series.reduce((sums, item) => sums.set(item.name, (sums.get(item.name) || 0) + item.value), sums)
, new Map)
result = Array.from(result.entries(), ([name, value]) => ({name, value}))
console.log(result)
Upvotes: 1
Reputation: 11116
You can do this by utilizing .reduce()
and .map()
.
The idea is to create a map of each unique date and the running total of that date's value for all data sets passed into the function, which would look something like so:
{
"my-date-1": 3000,
"my-date-2": 7500,
...
}
Then, once you have your unique set of dates and their total values, you can simply map them into the output you desire.
The benefit of this approach is that it is dynamic in the sense that you can pass in as many data sets as you'd like, the data sets can be in any order with any length, and you can pass in which property you'd like to group by. In this case, I just passed in the two datasets and told it to group on the "name" property.
function combineProps(propToMatch, ...dataSets) {
return Object.entries(dataSets.reduce((res, curr) => {
// sum each unique propToMatch value with the object's .value
curr.forEach(obj => {
var prop = obj[propToMatch];
// if prop doesn't exist yet, create it
if (!res[prop]) {
res[prop] = 0;
}
// add to rolling total
res[prop] += obj.value;
});
// return updated object
return res;
}, {}))
// then map to desired output format
.map(([name, value]) => ({value, name}));
}
const series_0 = [
{
'value': 3000,
'name': '2016-09-20T20:23:48.426Z'
},
{
'value': 6000,
'name': '2016-09-21T08:58:04.100Z'
},
{
'value': 4000,
'name': '2016-09-21T05:21:08.317Z'
},
{
'value': 6000,
'name': '2016-09-19T11:26:36.302Z'
},
{
'value': 5000,
'name': '2016-09-16T11:26:19.165Z'
}
]
const series_1 = [
{
'value': 3000,
'name': '2016-09-20T20:23:48.426Z'
},
{
'value': 1500,
'name': '2016-09-21T08:58:04.100Z'
},
{
'value': 8000,
'name': '2016-09-19T11:26:36.302Z'
},
];
console.log(combineProps("name", series_0, series_1));
Upvotes: 1
Reputation: 56744
There's probably many ways to achieve that, here's my approach:
const series_0 = [{
'value': 3000,
'name': '2016-09-20T20:23:48.426Z'
}, {
'value': 6000,
'name': '2016-09-21T08:58:04.100Z'
}, {
'value': 4000,
'name': '2016-09-21T05:21:08.317Z'
}, {
'value': 6000,
'name': '2016-09-19T11:26:36.302Z'
}, {
'value': 5000,
'name': '2016-09-16T11:26:19.165Z'
}]
const series_1 = [{
'value': 3000,
'name': '2016-09-20T20:23:48.426Z'
}, {
'value': 1500,
'name': '2016-09-21T08:58:04.100Z'
}, {
'value': 8000,
'name': '2016-09-19T11:26:36.302Z'
}, ]
//make sure the longer array is the outer for-loop-variable
const s0 = series_0.length >= series_1.length ? series_0 : series_1;
const s1 = series_0.length >= series_1.length ? series_1 : series_0;
let res = [];
for (const s of s0) {
let resObj = {name: s.name, value: s.value};
for (const t of s1) {
if (s.name === t.name) {
resObj.value+=t.value
}
}
res.push(resObj);
}
console.log(res);
Upvotes: 2