
本文介绍一种基于相邻元素差值判断的动态分组方法,用于将有序数组按 estimated_stay_time 的增量范围(如 100000)进行连续聚类,严格保持 detected_time 的原始顺序,且仅向前合并、不回溯。
本文介绍一种基于相邻元素差值判断的动态分组方法,用于将有序数组按 `estimated_stay_time` 的增量范围(如 100000)进行连续聚类,严格保持 `detected_time` 的原始顺序,且仅向前合并、不回溯。
在实际业务场景中(如设备停留时长分析、传感器事件聚合),我们常需对时间序列数据进行“有约束的分组”:既要满足数值范围条件(如相邻项 estimated_stay_time 差值 ≤ extension_window),又必须严格遵循原始时间顺序(detected_time 递增),禁止跨序重排或向后回溯归并。这不同于常规的 groupBy 或哈希分桶,而是一种顺序敏感的贪心聚类(greedy sequential clustering)。
核心逻辑如下:
- 遍历数组,对每个元素计算其与前一项 estimated_stay_time 的差值(delta);
- 若为首个元素(i === 0)、差值为负(时间倒退,异常但需容错)、或差值超过 extension_window(超出允许波动范围),则开启新分组;
- 否则,将当前元素追加至上一个分组末尾;
- 始终只依赖前一项状态,确保 O(n) 时间复杂度与单次遍历完成。
以下是完整可运行的实现代码:
const data = [
{ detected_time: 1, estimated_stay_time: 300, extension_window: 100000 },
{ detected_time: 2, estimated_stay_time: 330000, extension_window: 100000 },
{ detected_time: 3, estimated_stay_time: 130000, extension_window: 100000 },
{ detected_time: 4, estimated_stay_time: 150000, extension_window: 100000 },
{ detected_time: 5, estimated_stay_time: 3000, extension_window: 100000 },
{ detected_time: 6, estimated_stay_time: 591988, extension_window: 100000 },
{ detected_time: 7, estimated_stay_time: 663913, extension_window: 100000 }
];
const groupByTimeRange = (arr, windowKey = 'extension_window') => {
return arr.reduce((groups, item, index, array) => {
const prevItem = array[index - 1];
const delta = item.estimated_stay_time - (prevItem?.estimated_stay_time ?? 0);
const threshold = item[windowKey] ?? 100000;
if (index === 0 || delta threshold) {
groups.push([item]);
} else {
groups[groups.length - 1].push(item);
}
return groups;
}, []);
};
const result = groupByTimeRange(data);
console.log(JSON.stringify(result, null, 2));
✅ 关键特性说明:
- ✅ 顺序不可逆:完全尊重 detected_time 的输入顺序,不排序、不索引重映射;
- ✅ 前向单向合并:仅当当前项与前一项满足 delta ≤ extension_window 时才合并,绝不检查后续项或回填前组;
- ✅ 鲁棒性设计:自动处理首项初始化、负差值(数据异常)、extension_window 缺失等边界情况;
- ✅ 灵活扩展:可通过 windowKey 参数动态指定阈值字段(如支持不同 item 使用不同窗口)。
⚠️ 注意事项:
- 该算法假设 estimated_stay_time 具有业务语义上的“趋势性”,若存在大量随机跳变,分组结果可能较碎;此时建议先做轻量平滑或异常值过滤;
- extension_window 是每个 item 独立生效的阈值(非全局统一值),符合题设中各对象自带 extension_window: 100000 的设计;
- 如需改为“以首项为基准的固定区间分桶”(如 [0,100000), [100000,200000)...),应使用 Math.floor(item.estimated_stay_time / 100000) 分组,而非本方案。
此方法兼顾性能、可读性与业务准确性,是处理带时序约束的动态区间聚类问题的推荐实践。










