Reputation: 628
I'd like to sum objects from array, I've been searching and testing different things founds around there, using Lodash or not, without any success.
Here is the data array, there is 5 elements but it could be less or more. The properties will always be the same, but there could be a lot more.
const data = [
{
from: "2019-10-15",
stats: [
{
options: {
width: 15,
height: 20,
borders: 35,
removable: 5
}
}
]
},
{
from: "2019-10-16",
stats: [
{
options: {
width: 22,
height: 18,
borders: 10,
removable: 0
}
}
]
},
{
from: "2019-10-17",
stats: [
{
options: {
width: 0,
height: 15,
borders: 15,
removable: 0
}
}
]
},
{
from: "2019-10-18",
stats: [
{
options: {
width: 20,
height: 20,
borders: 10,
removable: 5,
}
}
]
},
{
from: "2019-10-19",
stats: [
{
options: {
width: 0,
height: 10,
borders: 0,
removable: 30
}
}
]
}
];
The expected result is the sum of each array element stats[0].options
properties:
const sum = {
width: 57,
height: 83,
borders: 70,
removable: 40
}
I know it's definitely not complicated.
Upvotes: 0
Views: 849
Reputation: 662
Another approach to do this with a reduce
and nested forEach
, but a bit more straightforward:
const data = [
{
from: "2019-10-15",
stats: [
{
options: {
width: 15,
height: 20,
borders: 35,
removable: 5
}
}
]
},
{
from: "2019-10-16",
stats: [
{
options: {
width: 22,
height: 18,
borders: 10,
removable: 0
}
}
]
},
{
from: "2019-10-17",
stats: [
{
options: {
width: 0,
height: 15,
borders: 15,
removable: 0
}
}
]
},
{
from: "2019-10-18",
stats: [
{
options: {
width: 20,
height: 20,
borders: 10,
removable: 5,
}
}
]
},
{
from: "2019-10-19",
stats: [
{
options: {
width: 0,
height: 10,
borders: 0,
removable: 30
}
}
]
}
];
let result = _.reduce(data, (acc, value) =>{
// our nested options object
const options = value.stats[0].options;
_.forEach(options, (optionValue, optionKey) =>{
// if we know about this key already, then add optionValue to it
// if not, this will be our first value for that key
acc[optionKey] = !!acc[optionKey] ? acc[optionKey] + optionValue : optionValue;
})
return acc;
}, {})
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>
Upvotes: 0
Reputation: 191936
Use _.map()
to get the options
, then combine the objects using _.mergeWith()
, and use _.add()
as the customizer.
const data = [{"from":"2019-10-15","stats":[{"options":{"width":15,"height":20,"borders":35,"removable":5}}]},{"from":"2019-10-16","stats":[{"options":{"width":22,"height":18,"borders":10,"removable":0}}]},{"from":"2019-10-17","stats":[{"options":{"width":0,"height":15,"borders":15,"removable":0}}]},{"from":"2019-10-18","stats":[{"options":{"width":20,"height":20,"borders":10,"removable":5}}]},{"from":"2019-10-19","stats":[{"options":{"width":0,"height":10,"borders":0,"removable":30}}]}];
const result = _.mergeWith({}, ..._.map(data, 'stats[0].options'), _.add);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>
If you use lodash/fp you can create a function using _.flow()
, and replace _.mergeWith
with _.mergeAllWith()
:
const { flow, map, mergeAllWith, add } = _;
const fn = flow(
map('stats[0].options'),
mergeAllWith(add)
);
const data = [{"from":"2019-10-15","stats":[{"options":{"width":15,"height":20,"borders":35,"removable":5}}]},{"from":"2019-10-16","stats":[{"options":{"width":22,"height":18,"borders":10,"removable":0}}]},{"from":"2019-10-17","stats":[{"options":{"width":0,"height":15,"borders":15,"removable":0}}]},{"from":"2019-10-18","stats":[{"options":{"width":20,"height":20,"borders":10,"removable":5}}]},{"from":"2019-10-19","stats":[{"options":{"width":0,"height":10,"borders":0,"removable":30}}]}];
const result = fn(data);
console.log(result);
<script src='https://cdn.jsdelivr.net/g/lodash@4(lodash.min.js+lodash.fp.min.js)'></script>
Upvotes: 3
Reputation: 38094
It can be done through vanill JavaScript. Just use reduce
and foreach
methods:
const data = [
{
from: "2019-10-15",
stats: [
{
options: {
width: 15,
height: 20,
borders: 35,
removable: 5
}
}
]
},
{
from: "2019-10-16",
stats: [
{
options: {
width: 22,
height: 18,
borders: 10,
removable: 0
}
}
]
},
{
from: "2019-10-17",
stats: [
{
options: {
width: 0,
height: 15,
borders: 15,
removable: 0
}
}
]
},
{
from: "2019-10-18",
stats: [
{
options: {
width: 20,
height: 20,
borders: 10,
removable: 5,
}
}
]
},
{
from: "2019-10-19",
stats: [
{
options: {
width: 0,
height: 10,
borders: 0,
removable: 30
}
}
]
}
];
const result = data.reduce((a, {stats}) => {
stats.forEach(({options}) => {
for (const key in options) {
a[key] = a[key] || 0;
a[key] += options[key];
}
});
return a;
}, {})
console.log(result);
The vanilla JS code looks like this:
const result = data.reduce((a, {stats}) => {
stats.forEach(({options}) => {
for (const key in options) {
a[key] = a[key] || 0;
a[key] += options[key];
}
});
return a;
}, {})
Upvotes: 2