Reputation: 1685
I have the following array:
[
{category: 'Category 1', data: [ {date: '01/04/2021', value: 10}, {date: '01/03/2021', value: 20}, {date: '01/02/2021', value: 5}] },
{category: 'Category 2', data: [ {date: '01/04/2021', value: 8}, {date: '01/03/2021', value: 2}, {date: '01/02/2021', value: 15}] },
{category: 'Category 3', data: [ {date: '01/04/2021', value: 7}, {date: '01/03/2021', value: 1}, {date: '01/02/2021', value: 5}] }
]
I would like to add a total row containing sum of values for each date for categories.
Example:
[
{category: 'Category 1', data: [ {date: '01/04/2021', value: 10}, {date: '01/03/2021', value: 20}, {date: '01/02/2021', value: 5}] },
{category: 'Category 2', data: [ {date: '01/04/2021', value: 8}, {date: '01/03/2021', value: 2}, {date: '01/02/2021', value: 15}] },
{category: 'Category 3', data: [ {date: '01/04/2021', value: 7}, {date: '01/03/2021', value: 1}, {date: '01/02/2021', value: 5}] },
{category: 'Total', data: [ {date: '01/04/2021', value: 25}, {date: '01/03/2021', value: 23}, {date: '01/02/2021', value: 30}] }
]
I am using the following code to do calculate the total:
const totalRow = categories.reduce((acc, curr) => {
if(!acc['data']) {
acc['data'] = [];
}
curr.data.forEach(d => {
if(!acc['data'].find(a => a.date == d.date)) {
acc['data'].push(d);
} else {
let monthData = acc['data'].find(a => a.date == d.date);
monthData.value += d.value;
}
});
return acc;
}, {});
categories.push({category: 'Total', ...totalRow});
However, the total row only contains Category 1 values.
How can I fix this? Also, is there a better way to calculate the total row?
Upvotes: 1
Views: 423
Reputation: 14228
You can try this way.
const data = [{category:'Category 1',data:[{date:'01/04/2021',value:10},{date:'01/03/2021',value:20},{date:'01/02/2021',value:5}]},{category:'Category 2',data:[{date:'01/04/2021',value:8},{date:'01/03/2021',value:2},{date:'01/02/2021',value:15}]},{category:'Category 3',data:[{date:'01/04/2021',value:7},{date:'01/03/2021',value:1},{date:'01/02/2021',value:5}]}];
const total = data.reduce((acc, {data}) => {
for(const {date, value} of data){
acc[date] ??= {date: date, value: 0};
acc[date].value += value;
}
return acc;
}, {});
console.log([...data, {category: 'Total', data: Object.values(total)}]);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Upvotes: 1
Reputation: 26170
This could be done as follows:
const categories = [
{category: 'Category 1', data: [ {date: '01/04/2021', value: 10}, {date: '01/03/2021', value: 20}, {date: '01/02/2021', value: 5}] },
{category: 'Category 2', data: [ {date: '01/04/2021', value: 8}, {date: '01/03/2021', value: 2}, {date: '01/02/2021', value: 15}] },
{category: 'Category 3', data: [ {date: '01/04/2021', value: 7}, {date: '01/03/2021', value: 1}, {date: '01/02/2021', value: 5}] }
];
const totalData = categories.map(o => o.data)
.flat()
.reduce((acc, v) => {
const existing = acc.find(e => e.date == v.date);
if (existing) {
existing.value += v.value;
} else {
acc.push(JSON.parse(JSON.stringify(v)));
}
return acc;
}, []);
categories.push({ category: 'Total', data: totalData });
console.log(categories)
Note that I'm using
acc.push(JSON.parse(JSON.stringify(v)));
in order to avoid the logging issue described here.
Stack Snippets logging nested objects weirdly
Upvotes: 2
Reputation: 1122
const categories = [{
category: 'Category 1',
data: [{
date: '01/04/2021',
value: 10
}, {
date: '01/03/2021',
value: 20
}, {
date: '01/02/2021',
value: 5
}]
},
{
category: 'Category 2',
data: [{
date: '01/04/2021',
value: 8
}, {
date: '01/03/2021',
value: 2
}, {
date: '01/02/2021',
value: 15
}]
},
{
category: 'Category 3',
data: [{
date: '01/04/2021',
value: 7
}, {
date: '01/03/2021',
value: 1
}, {
date: '01/02/2021',
value: 5
}]
}
]
const totalRow = categories.reduce((acc, curr) => {
return curr.data.map(x => {
const y = acc.find(i => i.date === x.date);
return y ? {
...x,
value: x.value + y.value
} : x
});
}, []);
categories.push({
category: 'Total',
data: totalRow
});
console.log(categories);
Upvotes: 1
Reputation: 8188
This how I achieved the desired results:
const data = [
{
category: 'Category 1',
data: [
{ date: '01/04/2021', value: 10 },
{ date: '01/03/2021', value: 20 },
{ date: '01/02/2021', value: 5 },
],
},
{
category: 'Category 2',
data: [
{ date: '01/04/2021', value: 8 },
{ date: '01/03/2021', value: 2 },
{ date: '01/02/2021', value: 15 },
],
},
{
category: 'Category 3',
data: [
{ date: '01/04/2021', value: 7 },
{ date: '01/03/2021', value: 1 },
{ date: '01/02/2021', value: 5 },
],
},
];
data.push(
data.reduce(
(res, { data }) => (
data.forEach((d) => {
res.data.find((r) => r.date === d.date)
? (res.data.find((r) => r.date === d.date).value += d.value)
: res.data.push({ ...d });
}),
res
),
{ category: 'Total', data: [] }
)
);
console.log(data);
Upvotes: 1