My solution may need some altering based on your date type (if it's not a string, the key should be converted to a string in the reduce part the logic to work). Also, I assumed that your date key name is "date". But basically, this is my solution (and here's a sandbox if you want to toy with it):
return Object.values(
this.materialList
.map((mat) =>
mat.prices.map((price) => ({
price: price.price * mat.pivots.percentages / 100,
date: price.date,
}))
)
.flat()
.reduce((accumulator, price) => {
const key = price.date;
if (!accumulator[key]) {
accumulator[key] = price;
} else {
accumulator[key].price += price.price;
}
return accumulator;
}, {})
);
You might be like "woah there!", so here's what's going on:
- First of all, in the map portion, you iterate over each material and then map each prices into basically the same price structure, but with the price that has been multiplied by the percentages. At this point, this is what you get:
[
[
{
"price": 3.9,
"date": "2021-03-01"
},
{
"price": 3.9,
"date": "2021-04-01"
},
{
"price": 5.1,
"date": "2021-05-01"
},
{
"price": 3.3,
"date": "2021-06-01"
},
{
"price": 5.7,
"date": "2021-07-01"
}
],
[
{
"price": 2,
"date": "2021-03-01"
},
{
"price": 2,
"date": "2021-04-01"
},
{
"price": 2.6,
"date": "2021-05-01"
},
{
"price": 2.2,
"date": "2021-06-01"
},
{
"price": 2,
"date": "2021-07-01"
}
]
]
- Then, you can see that you have an unnecessary level of arrays, so then you call
.flat()on that result, which gives you:
[
{
"price": 3.9,
"date": "2021-03-01"
},
{
"price": 3.9,
"date": "2021-04-01"
},
{
"price": 5.1,
"date": "2021-05-01"
},
{
"price": 3.3,
"date": "2021-06-01"
},
{
"price": 5.7,
"date": "2021-07-01"
},
{
"price": 2,
"date": "2021-03-01"
},
{
"price": 2,
"date": "2021-04-01"
},
{
"price": 2.6,
"date": "2021-05-01"
},
{
"price": 2.2,
"date": "2021-06-01"
},
{
"price": 2,
"date": "2021-07-01"
}
]
- With all prices at the same level, you can now use reduce to build an object keyed by the price date. If no key matches the date, create a new property with the date as the key and the entire price object as the value. Else, if there is actually a key matching the date, simply increment its price by the currently iterated price object's price. That gives us the following object:
{
"2021-03-01": {
"price": 5.9,
"date": "2021-03-01"
},
"2021-04-01": {
"price": 5.9,
"date": "2021-04-01"
},
"2021-05-01": {
"price": 7.699999999999999,
"date": "2021-05-01"
},
"2021-06-01": {
"price": 5.5,
"date": "2021-06-01"
},
"2021-07-01": {
"price": 7.7,
"date": "2021-07-01"
}
}
- Finally, you probably want the prices as an array for easier manipulation, so that's what
Object.valuesdoes. And there it is, the final result:
[
{
"price": 5.9,
"date": "2021-03-01"
},
{
"price": 5.9,
"date": "2021-04-01"
},
{
"price": 7.699999999999999,
"date": "2021-05-01"
},
{
"price": 5.5,
"date": "2021-06-01"
},
{
"price": 7.7,
"date": "2021-07-01"
}
]
P.S. Of course you should probably round prices afterwards because floats are not 100% precise, so they can cause the problem you see on May 1st.