
本文介绍如何在 JavaScript 中高效地对多个不等长的时间序列数组(以 [timestamp, value] 形式存储)按时间戳对齐并计算各时间点的平均值,无需依赖 Lodash,仅用原生方法即可实现高性能聚合。
本文介绍如何在 javascript 中高效地对多个不等长的时间序列数组(以 `[timestamp, value]` 形式存储)按时间戳对齐并计算各时间点的平均值,无需依赖 lodash,仅用原生方法即可实现高性能聚合。
在时序数据分析场景中(如传感器采集、日志指标聚合或金融行情对齐),常遇到多组长度不一、但共享同一时间轴的数据——部分时间点在某些序列中缺失。此时,直接按索引平均毫无意义;真正需要的是以时间戳为键,聚合所有可用观测值并求均值。下面提供一个简洁、健壮、零依赖的原生 JavaScript 实现方案。
核心思路:分三步完成聚合
- 扁平化合并:将所有时间序列数组展开为单一二维数组;
- 按时间戳分组:使用对象({ timestamp: [value1, value2, ...] })归集同时间点的所有数值;
- 计算均值并格式化输出:遍历分组对象,对每个时间戳下的数值数组求平均,并还原为 [timestamp, avgValue] 的二维数组结构。
完整实现代码
const array1 = [[1, 100], [2, 200], [3, 300], [4, 400]];
const array2 = [[1, 150], [3, 350], [4, 450]];
const array3 = [[1, 250], [2, 350], [4, 450]];
const allArrays = [array1, array2, array3];
// 步骤1 & 2:扁平化 + 按时间戳分组(使用 reduce + nullish coalescing assignment)
const groupedByTime = allArrays
.flat() // 替代 [...array1, ...array2, ...array3],更简洁且支持任意数量数组
.reduce((acc, [time, value]) => {
(acc[time] ??= []).push(value);
return acc;
}, {});
// 步骤3:计算平均值,生成目标格式结果(保留一位小数,时间转为 number 类型)
const averagedResult = Object.entries(groupedByTime)
.map(([timeStr, values]) => {
const avg = values.reduce((sum, v) => sum + v, 0) / values.length;
return [Number(timeStr), parseFloat(avg.toFixed(1))]; // toFixed 返回字符串,故用 parseFloat 确保数值类型
})
.sort((a, b) => a[0] - b[0]); // 可选:按时间戳升序排列,保证输出有序
console.log(averagedResult);
// 输出: [[1, 166.7], [2, 275], [3, 325], [4, 433.3]]关键技术点说明
- ✅ Array.prototype.flat():替代手动展开,天然支持嵌套层级可控的扁平化(默认深度 1),语义清晰且兼容性良好(ES2019+,现代浏览器及 Node.js ≥12 均支持)。
- ✅ ??=(空值合并赋值):确保 acc[time] 初始化为空数组,避免重复判断 if (!acc[time]) acc[time] = [],提升可读性与性能。
- ✅ parseFloat(avg.toFixed(1)):toFixed() 返回字符串,若后续需参与数值运算(如再平均、绘图库输入),应显式转回 number;parseFloat 比 Number() 更安全(对空字符串返回 NaN 而非 0,便于错误发现)。
- ✅ .sort() 补充:因 Object.entries() 不保证键顺序,添加排序可确保结果严格按时间递增,符合时间序列惯例。
注意事项与扩展建议
-
时间精度处理:若时间戳为毫秒级浮点数(如 Date.now()),建议先四舍五入到秒或毫秒粒度再分组,避免浮点误差导致误判为不同时间点:
const roundedTime = Math.round(time / 1000) * 1000; // 对齐到秒
- 缺失值容忍:当前逻辑自动跳过缺失时间点(即仅聚合存在的数据),符合题设要求;如需补零或插值,应在分组前注入默认值。
-
大数据量优化:当数组极长(>10⁵ 项)时,可考虑使用 Map 替代普通对象(避免原型链干扰、支持任意键类型),性能更稳定:
const grouped = allArrays.flat().reduce((map, [t, v]) => { const list = map.get(t) ?? []; list.push(v); return map.set(t, list); }, new Map());
该方案兼具简洁性、可维护性与生产就绪性,适用于前端可视化预处理、Node.js 后端指标聚合等典型场景。









