如何基于人员进出记录计算指定时段房间最高occupancy及平均人数
进出人数统计正确实现方案
原有代码问题说明
- 连续三次排序逻辑无效:后一次排序会直接覆盖前两次的排序结果,前两次排序没有任何作用
- 核心思路错误:你试图通过提取最高进入量、最低离开量计算峰值的逻辑不符合实际场景,累计进入量最高的时间点,累计离开量可能也处于高位,最终对应的在室人数不一定是周期内的最大值。
前置数据约定
你拿到的results数组为45分钟统计周期内的所有上报记录,单条记录的enter为从统计周期启动到当前上报时间的累计进入人数,exit为同期累计离开人数,每条记录需包含上报时间戳t(单位统一即可,如分钟、毫秒)。如果上报本身是按时间顺序生成的,可以省略时间排序步骤。
核心计算逻辑
1. 最高在室人数计算
遍历所有记录,逐行计算当前在室人数,全程记录最大值即可,时间复杂度O(n),完全适配你50~100条的数据量。
2. 平均在室人数计算
采用时间加权计算,避免事件上报密度不均导致的统计偏差:
- 按时间先后顺序排列所有上报记录
- 计算相邻两次上报的时间间隔,用上一个时间点的在室人数乘以间隔时长,得到该时段的加权人数
- 所有时段加权人数求和后,除以45分钟的总时长,得到平均在室人数
修正后代码示例
.then((results) => { // 先按上报时间从小到大排序,如果results本身是按时间顺序上报的可以删除这行 results.sort((a, b) => a.t - b.t); let maxOccupancy = 0; let timeWeightedTotal = 0; // 统计周期开始时间,可根据实际业务赋值,这里假设第一条记录的时间就是周期开始时间 let prevTime = results[0]?.t || 0; let prevCount = 0; // 周期初始在室人数,无人默认0 const totalDuration = 45 * 60 * 1000; // 45分钟转毫秒,和时间戳单位对齐 for (const record of results) { const currentCount = record.enter - record.exit; // 更新最高在室人数 if (currentCount > maxOccupancy) { maxOccupancy = currentCount; } // 累加时间加权人数 const delta = record.t - prevTime; timeWeightedTotal += prevCount * delta; // 更新上一个节点的时间和人数 prevTime = record.t; prevCount = currentCount; } // 补充最后一条记录到统计周期结束的加权值 const finalDelta = (results[0]?.t || 0) + totalDuration - prevTime; timeWeightedTotal += prevCount * finalDelta; // 计算平均人数,保留2位小数可按需调整 const avgOccupancy = +(timeWeightedTotal / totalDuration).toFixed(2); // 仅需要最高值直接返回maxOccupancy即可,这里返回两个结果 return { maxOccupancy, avgOccupancy }; })
简化场景适配
如果你的上报是固定间隔触发(比如每30秒上报一次),不需要精确时间加权的话,平均人数可以简化为所有记录的在室人数之和除以记录总数:
.then((results) => { let maxOccupancy = 0; let countSum = 0; for (const record of results) { const currentCount = record.enter - record.exit; maxOccupancy = Math.max(maxOccupancy, currentCount); countSum += currentCount; } const avgOccupancy = results.length ? +(countSum / results.length).toFixed(2) : 0; return { maxOccupancy, avgOccupancy }; })
内容的提问来源于stack exchange,提问作者Avi Teller
相关产品推荐
相关产品推荐

