JavaScript按工作日+半小时区间聚合handled值异常问题
问题分析与解决方案:按工作日+半小时区间聚合数据
首先,你的核心问题有两个:所有工作日共享了同一个intervalObj引用,以及冗余的循环逻辑导致不必要的遍历。我们一步步来解决:
1. 根本问题:对象引用共享导致批量修改
你最初创建intervalObj后,直接把它赋值给每个工作日的data属性:
for (i = 1; i <= 5; i++) { hhObj.push({ day: i, data: intervalObj }) }
在JavaScript中,数组是引用类型,这意味着所有工作日的data都指向同一个内存地址的数组。所以你修改任意一个工作日的区间数据时,其他所有工作日的对应数据都会跟着改变——这就是为什么所有工作日的相同区间会出现重复的求和结果。
解决方法:为每个工作日创建独立的区间数组副本
我们需要给每个工作日生成一个intervalObj的独立副本,确保它们互不影响:
// 固定的半小时区间数组 const halfHours = ["00:00", "00:30", "01:00", "01:30", "02:00", "02:30", "03:00", "03:30", "04:00", "04:30", "05:00", "05:30", "06:00", "06:30", "07:00", "07:30", "08:00", "08:30", "09:00", "09:30", "10:00", "10:30", "11:00", "11:30", "12:00", "12:30", "13:00", "13:30", "14:00", "14:30", "15:00", "15:30", "16:00", "16:30", "17:00", "17:30", "18:00", "18:30", "19:00", "19:30", "20:00", "20:30", "21:00", "21:30", "22:00", "22:30", "23:00", "23:30"]; // 创建基础区间模板 const intervalObj = halfHours.map(interval => ({ interval: interval, answered: 0, handled: 0 })); // 为每个工作日创建独立的区间数组 const hhObj = []; for (let i = 1; i <= 5; i++) { // 使用展开运算符浅拷贝模板数组(因为数组项都是基本类型,浅拷贝足够) const dayIntervalData = intervalObj.map(item => ({...item})); hhObj.push({ day: i, data: dayIntervalData }); }
2. 优化循环逻辑:减少冗余遍历
你原来的内层循环遍历了所有5个工作日,这完全没必要——我们可以直接根据当前数据的工作日,定位到hhObj中对应的对象,再找到匹配的区间进行累加。
另外注意:Date.getDay()返回的是0(周日)到6(周六),而你的hhObj是1-5对应周一到周五,所以需要过滤掉周日和周六的数据。同时,半小时区间的判断可以更严谨(比如把0-29分归到00区间,30-59分归到30区间)。
修正后的数据聚合逻辑
const test = [ {"DateTime":"5/1/18 03:00:00 AM","Answered":"0","handled":"3"}, {"DateTime":"5/3/18 10:00:00 AM","Answered":"0","handled":"1"}, {"DateTime":"5/2/18 07:00:00 AM","Answered":"0","handled":"25"}, {"DateTime":"5/5/18 12:00:00 AM","Answered":"0","handled":"2"}, {"DateTime":"5/10/18 12:00:00 AM","Answered":"0","handled":"6"}, {"DateTime":"5/12/18 07:00:00 AM","Answered":"0","handled":"1"}, {"DateTime":"5/13/18 12:00:00 AM","Answered":"0","handled":"12"}, {"DateTime":"5/1/18 07:00:00 AM","Answered":"0","handled":"5"}, {"DateTime":"5/6/18 10:00:00 AM","Answered":"0","handled":"1"}, {"DateTime":"5/7/18 12:00:00 AM","Answered":"0","handled":"2"}, {"DateTime":"5/3/18 12:00:00 AM","Answered":"0","handled":"0"}, {"DateTime":"5/18/18 06:00:00 AM","Answered":"0","handled":"14"}, {"DateTime":"5/12/18 12:30:00 AM","Answered":"0","handled":"1"} ]; for (const row of test) { const dt = new Date(row.DateTime); const weekDay = dt.getDay(); // 只处理周一到周五(weekDay 1-5),跳过周日(0)和周六(6) if (weekDay < 1 || weekDay > 5) continue; // 计算对应的半小时区间 let hh = dt.getHours(); if (hh < 10) hh = `0${hh}`; const mm = dt.getMinutes() < 30 ? '00' : '30'; const timeInterval = `${hh}:${mm}`; const handled = parseInt(row.handled, 10); if (isNaN(handled)) continue; // 跳过无效数值 // 定位到当前工作日的data数组 const dayIdx = weekDay - 1; // day1对应索引0,day5对应索引4 const targetDayData = hhObj[dayIdx].data; // 找到匹配的区间并累加handled值 const targetInterval = targetDayData.find(item => item.interval === timeInterval); if (targetInterval) { targetInterval.handled += handled; } }
最终效果
修正后,每个工作日的data数组都是独立的,累加操作只会影响对应工作日的对应区间,不会出现所有工作日重复相同结果的问题,完全符合你的预期结构。
内容的提问来源于stack exchange,提问作者oceansmoving
相关产品推荐
相关产品推荐

