You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何更优雅地将1分钟时间序列数组聚合为5分钟数据?

1分钟步长时间序列聚合为5分钟数据的简洁实现

作为编程初学者,我发现很多开发者都在讨论将1分钟步长的时间序列数据聚合为5分钟数据的问题。我需要把包含steps(步数)和created_at(时间戳)的1分钟数据数组转换为5分钟粒度的数据:对连续5分钟的steps求和,created_at取该5分钟时段的结束时间。目前我的实现方案较为繁琐,附上原数据、现有代码及期望结果,希望找到更简洁的单遍处理方法。

原数据

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' }
]

现有实现代码

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}    
        }
    );

const reducedArray = Array.from(newArray.reduce(
    (m, {timeStampgroup: timeStampgroup, steps}) => m.set(timeStampgroup, (m.get(timeStampgroup) || 0) + steps), new Map
  ), ([timeStampgroup, steps]) => ({timeStampgroup, steps}));

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' }
]

简洁的单遍处理方案

方案1:基于时间分组(兼容数据缺失场景)

使用reduce单遍遍历数组,通过对象映射存储分组信息,最终转换为结果数组,无需多次遍历:

const moment = require('moment');

const result = Object.values(array.reduce((groups, item) => {
  // 计算当前数据所属5分钟时段的结束时间
  const minute = moment(item.created_at).minute();
  const endMinute = Math.ceil(minute / 5) * 5;
  const endTime = moment(item.created_at)
    .startOf('minute')
    .set('minute', endMinute)
    .toISOString();

  // 更新分组的步数总和
  if (!groups[endTime]) {
    groups[endTime] = { steps: 0, created_at: endTime };
  }
  groups[endTime].steps += item.steps;

  return groups;
}, {}));

console.log(result);

方案2:基于索引分组(仅适用于连续无缺失的1分钟数据)

如果你的数据是严格连续的1分钟记录,没有缺失项,可以直接按每5个元素一组处理,代码更简洁:

const result = [];
for (let i = 0; i < array.length; i += 5) {
  const group = array.slice(i, i + 5);
  const totalSteps = group.reduce((sum, item) => sum + item.steps, 0);
  // 取分组最后一个元素的created_at作为时段结束时间
  result.push({ steps: totalSteps, created_at: group.at(-1).created_at });
}

console.log(result);

这两个方案都只需要遍历数组一次(方案2的内部reduce是小范围遍历,整体复杂度更低),比原代码的三次遍历更高效简洁。


内容的提问来源于stack exchange,提问作者Lorenzo Sandini

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 10:03:32