Reputation: 695
So first of all, because I am using a ChartJS
I need to generate an array of months.
The creation is looking like this :
const [generatedMonths, setGeneratedMonths] = useState<string[]>([])
const [totalValues, setTotalValues] = useState<number[]>([])
const months = []
const dateStart = moment()
const dateEnd = moment().subtract(11, 'month')
while (dateEnd.isBefore(dateStart, 'day')) {
months.push(dateEnd.format('MMM'))
dateEnd.add(1, 'month')
}
months.push(dateEnd.format('MMM'))
setGeneratedMonths(months)
After that i receive my data like this :
const myArray = [
{date: "2022-04-13", vat_percentages: {21: 92.31}, total: 92.31}
{date: "2022-05-04", vat_percentages: {21: 21.24}, total: 21.24}
{date: "2022-05-05", vat_percentages: {21: 47.41}, total: 47.41}
]
Then in my useEffect
hook i am performing the sum :
useEffect(() => {
if (myArray.length > 0) {
const labelValues: number[] = generatedMonths.map(
(label, index) => {
const result = myArray.reduce((acc, curr) => {
const foundItem = acc.find(
(item) => item.date.format('MMM') === label
)
if (foundItem) {
foundItem.total += curr.total
} else {
acc.push(curr)
}
return acc
}, [])
}
)
setTotalValues(labelValues)
}
},[myArray])
So the final idea would be to have a sum for each month based on my find method based on the total
value. Like this:
console.log(totalValues)
// [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 92.31, 68.65]
Upvotes: 0
Views: 758
Reputation: 9168
You can massively simplify the solution using the fact that values for month are always going to be between 1-12 (inclusive). Therefore you can use an array of length 12 and use month - 1
as an index to update the sum for a given month.
const myArray = [{
date: "2022-04-13",
vat_percentages: {
21: 92.31
},
total: 92.31
}, {
date: "2022-05-04",
vat_percentages: {
21: 21.24
},
total: 21.24
}, {
date: "2022-05-05",
vat_percentages: {
21: 47.41
},
total: 47.41
}]
const labelValues = myArray.reduce((acc, curr) => {
// parse a month to number e.g. "04" => 4 then substract 1 to get the index within the array 4 - 1 => 3
const idx = Number(curr.date.split("-")[1]) - 1;
acc[idx] += curr.total;
return acc
}, new Array(12).fill(0))
console.log(labelValues)
.as-console-wrapper { max-height: 100% !important; top: 0; }
The output should be interpreted as follows:
0 (Jan) | 1 (Feb) | 2 (Mar) | 3 (Apr) | 4 (May) | 5 (Jun) | 6 (Jul) | 7 (Aug) | 8 (Sep) | 9 (Oct) | 10 (Nov) | 11 (De) |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 92.31 | 68.64999999999999 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
To reflect your requirement of having to set the values at certain positions according to generatedMonths
you could use simple modular arithmetic.
A position for a month is therefore obtained by (month + shiftValue) % 12
. To determine the shift value you just need to look at the first value in generatedMonths
and lookup which month of the year that is.
The rest works exactly like before:
const myArray = [{
date: "2022-04-13",
vat_percentages: {
21: 92.31
},
total: 92.31
}, {
date: "2022-05-04",
vat_percentages: {
21: 21.24
},
total: 21.24
}, {
date: "2022-05-05",
vat_percentages: {
21: 47.41
},
total: 47.41
}]
// mapping of month to shift value
const mapping = {
Jan: 0,
Feb: 11,
Mar: 10,
Apr: 9,
May: 8,
Jun: 7,
Jul: 6,
Aug: 5,
Sep: 4,
Oct: 3,
Nov: 2,
Dec: 1
};
// compute a shift value
const generatedMonths = ["Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "Jan", "Feb", "Mar", "Apr", "May"]
const shiftBy = mapping[generatedMonths[0]];
const labelValues = myArray.reduce((acc, curr) => {
// parse a month to number e.g. "04" => 4 then substract 1 to get the index within the array 4 - 1 => 3
const idx = (Number(curr.date.split("-")[1]) + shiftBy - 1) % 12;
acc[idx] += curr.total;
return acc
}, new Array(12).fill(0))
console.log(labelValues)
Upvotes: 1