So I have an peculiar set of data:
data: [
['2022-01-17T16:29:24', 30], // these below would aggregate to 210
['2022-01-17T17:37:24', 30],
['2022-01-17T17:41:40', 30],
['2022-01-17T17:41:48', 30],
['2022-01-21T12:50:18', 30],
['2022-01-21T12:50:18', 30],
['2022-01-21T12:50:29', 30],
['2022-01-12T12:50:18', 30], // these below would aggregate to 90
['2022-01-12T12:50:18', 30],
['2022-01-12T12:50:29', 30]
]
I would need to reduce this to sets of week data. I would convert dates to start of week to get the week data moment(day).startOf('isoWeek')
and then concat the data on similar dates and reduce it to single entry.
Ending result would look like:
data: [
['2022-01-17T00:00:00', 210],
['2022-01-10T00:00:00', 90]
]
But I am looking for suggestions how to use .reduce()
or any other more modern solutions for this that would be performant on large sets. Right now I have nested for loops for this which (aside from looking bad) probably perform quite poorly because it iterates multiple times over same array. One requirement is that moment
should be used for date manipulation, please try to avoid Date
obj's.
Right now I have something like this:
mergeDataToWeek(data: any[]) {
let reducedArrays = [];
for (let arr of data) {
if (moment(arr[0]).isValid() && arr[1] > 0) {
arr[0] = moment(arr[0]).startOf('isoWeek').toISOString(true);
if (!reducedArrays.some(reduced => reduced[0] == (arr[0]))) {
reducedArrays.push(arr);
} else {
let target = reducedArrays.find(reduced => reduced[0] == arr[0]);
target[1] = arr[1];
}
}
}
console.log(reducedArrays);
return reducedArrays;
}
CodePudding user response:
I'm trying to solve it using reduce, but the result will be an object. Like this:
const moment = require("moment")
var x = [
['2022-01-17T16:29:24', 30],
['2022-01-17T17:37:24', 30],
['2022-01-17T17:41:40', 30],
['2022-01-17T17:41:48', 30],
['2022-01-21T12:50:18', 30],
['2022-01-21T12:50:18', 30],
['2022-01-21T12:50:29', 30],
['2022-01-12T12:50:18', 30],
['2022-01-12T12:50:18', 30],
['2022-01-12T12:50:29', 30]
]
// solution
var y = x.reduce((a,b) => {
const key = moment(b[0]).startOf("isoWeek").format()
a[key] = a[key]? a[key] b[1]: b[1]
return a
}, {})
console.log(y)
Output:
{
"2022-01-17T00:00:00 07:00": 210,
"2022-01-10T00:00:00 07:00": 90
}
But if you want it as array as yours, we can convert it by:
var z = Object.keys(y).map(i => [i,y[i]])
// OR THIS -- Thanks to @ghybs
var z = Object.entries(y)
console.log(z)
Output:
[
[ '2022-01-17T00:00:00 07:00', 210 ],
[ '2022-01-10T00:00:00 07:00', 90 ]
]
Although it's not the best solution, but I think it will much more readable than nested loop.
CodePudding user response:
Run The Code
let x = [
['2022-01-17T16:29:24', 30],
['2022-01-17T17:37:24', 30],
['2022-01-17T17:41:40', 30],
['2022-01-17T17:41:48', 30],
['2022-01-21T12:50:18', 30],
['2022-01-21T12:50:18', 30],
['2022-01-21T12:50:29', 30],
['2022-01-12T12:50:18', 30],
['2022-01-12T12:50:18', 30],
['2022-01-12T12:50:29', 30]
]
// solution
const groupedTotal = x.reduce((a, b) => {
const key = moment(b[0]).startOf("isoWeek").format()
a[key] = a[key] ? a[key] b[1] : b[1]
return a
}, {});
const totals = Object.entries(groupedTotal);
console.log("Grouped Total:", groupedTotal, "\n Totals:", totals);
<script src="https://unpkg.com/[email protected]/moment.js"></script>
Note:- Code from @Rizal Ardhi Rahmadani...