I see many posts/questions addressing this issue, so I assume it is not trivial. I am quite a beginner, looking for a more elegant solution.
I need to reduce this kind of array containing 1-minute detailed data into 5-minute data. Just computing the sum of consecutive values for 5 minutes, and then recreating a shorter array. Then the timestamp "created_at" should be the timepoint of the end of the 5-minute period.
let array = [
{ steps: 40, created_at: '2022-09-03T11:36:00.000Z' },
{ steps: 13, created_at: '2022-09-03T11:37:00.000Z' },
{ steps: 40, created_at: '2022-09-03T11:38:00.000Z' },
{ steps: 40, created_at: '2022-09-03T11:39:00.000Z' },
{ steps: 34, created_at: '2022-09-03T11:40:00.000Z' },
{ steps: 86, created_at: '2022-09-03T11:41:00.000Z' },
{ steps: 23, created_at: '2022-09-03T11:42:00.000Z' },
{ steps: 78, created_at: '2022-09-03T11:43:00.000Z' },
{ steps: 67, created_at: '2022-09-03T11:44:00.000Z' },
{ steps: 80, created_at: '2022-09-03T11:45:00.000Z' },
{ steps: 34, created_at: '2022-09-03T11:46:00.000Z' },
{ steps: 64, created_at: '2022-09-03T11:47:00.000Z' },
{ steps: 32, created_at: '2022-09-03T11:48:00.000Z' },
{ steps: 78, created_at: '2022-09-03T11:49:00.000Z' },
{ steps: 45, created_at: '2022-09-03T11:50:00.000Z' }
]
My solution is too complex I think:
const moment = require(`moment`);
const newArray = array.map(
(item)=> {
const timestamp = moment(item.created_at).valueOf();
const timeStampgroup = Math.ceil((timestamp)/300000);
return {...item, timeStampgroup: timeStampgroup}
}
);
//console.log(newArray);
const reducedArray = Array.from(newArray.reduce(
(m, {timeStampgroup: timeStampgroup, steps}) => m.set(timeStampgroup, (m.get(timeStampgroup) || 0) steps), new Map
), ([timeStampgroup, steps]) => ({timeStampgroup, steps}));
//console.log(reducedArray);
const result = reducedArray.map(entry => ({steps : entry.steps, created_at : moment(entry.timeStampgroup*300000).toISOString()}));
console.log(result);
[
{ steps: 167, created_at: '2022-09-03T11:40:00.000Z' },
{ steps: 334, created_at: '2022-09-03T11:45:00.000Z' },
{ steps: 253, created_at: '2022-09-03T11:50:00.000Z' }
]
Does anyone see a less complicated way to achieve the same result, in one pass maybe ?
Thanks a lot !
Lorenzo
CodePudding user response:
const array = [
{ steps: 40, created_at: '2022-09-03T11:36:00.000Z' },
{ steps: 13, created_at: '2022-09-03T11:37:00.000Z' },
{ steps: 40, created_at: '2022-09-03T11:38:00.000Z' },
{ steps: 40, created_at: '2022-09-03T11:39:00.000Z' },
{ steps: 34, created_at: '2022-09-03T11:40:00.000Z' },
{ steps: 86, created_at: '2022-09-03T11:41:00.000Z' },
{ steps: 23, created_at: '2022-09-03T11:42:00.000Z' },
{ steps: 78, created_at: '2022-09-03T11:43:00.000Z' },
{ steps: 67, created_at: '2022-09-03T11:44:00.000Z' },
{ steps: 80, created_at: '2022-09-03T11:45:00.000Z' },
{ steps: 34, created_at: '2022-09-03T11:46:00.000Z' },
{ steps: 64, created_at: '2022-09-03T11:47:00.000Z' },
{ steps: 32, created_at: '2022-09-03T11:48:00.000Z' },
{ steps: 78, created_at: '2022-09-03T11:49:00.000Z' },
{ steps: 45, created_at: '2022-09-03T11:50:00.000Z' }
]
const reducedArr = Array.from(
array.reduce((m, item) => {
const date = new Date(item.created_at)
const key = Math.ceil(date.getMinutes()/5)*5;
return m.set(key, (m.get(key) || 0) item.steps)
}, new Map()),
([created_at, steps]) => ({ created_at, steps })
)
console.log(reducedArr);
I edited This answer from @some-user on this question to remove the need for moment import.
CodePudding user response:
Like this?
const moment = require(`moment`)
require('moment-round')
const array = [
{ steps: 40, created_at: '2022-09-03T11:36:00.000Z' },
{ steps: 13, created_at: '2022-09-03T11:37:00.000Z' },
{ steps: 40, created_at: '2022-09-03T11:38:00.000Z' },
{ steps: 40, created_at: '2022-09-03T11:39:00.000Z' },
{ steps: 34, created_at: '2022-09-03T11:40:00.000Z' },
{ steps: 86, created_at: '2022-09-03T11:41:00.000Z' },
{ steps: 23, created_at: '2022-09-03T11:42:00.000Z' },
{ steps: 78, created_at: '2022-09-03T11:43:00.000Z' },
{ steps: 67, created_at: '2022-09-03T11:44:00.000Z' },
{ steps: 80, created_at: '2022-09-03T11:45:00.000Z' },
{ steps: 34, created_at: '2022-09-03T11:46:00.000Z' },
{ steps: 64, created_at: '2022-09-03T11:47:00.000Z' },
{ steps: 32, created_at: '2022-09-03T11:48:00.000Z' },
{ steps: 78, created_at: '2022-09-03T11:49:00.000Z' },
{ steps: 45, created_at: '2022-09-03T11:50:00.000Z' },
]
const result = Array.from(
array.reduce((m, item) => {
const key = moment(item.created_at).ceil(5, 'minutes').toISOString()
return m.set(key, (m.get(key) || 0) item.steps)
}, new Map()),
([created_at, steps]) => ({ created_at, steps })
)
console.log(result)
CodePudding user response:
Assuming there are no gaps in the sequence, and that the array is sorted, you won't get a whole lot faster than this:
const results = [];
for (let i = 0; i < array.length; i = 5) {
const created_at = array[i].created_at;
const steps = array.slice(i, i 5).reduce((acc, item) => acc item.steps, 0);
results.push({ created_at, steps });
}