如何向含reportYear与reportWeek的对象数组补充缺失周数据?
补全缺失周的对象数组方案
嘿,这个需求我之前也碰到过,补全时间序列的缺失数据确实是报表场景里的常见需求。我给你写个JavaScript的实现方案,思路清晰还容易调整,你看看合不合适:
核心思路
- 先确定数据的时间范围(最早的周和最晚的周)
- 生成这个范围内的所有完整周序列(包括缺失的周)
- 把原数据转换成键值对结构,方便快速查找某一周是否存在
- 遍历完整序列,补全缺失的周数据,复用原数据的固定属性(比如员工信息)
代码实现
辅助工具函数
先写两个处理日期和周转换的工具函数,确保周数计算符合ISO标准(周一为一周的开始):
// 根据年份和周数,获取该周周一的UTC日期 function getDateOfWeek(year, week) { const d = new Date(Date.UTC(year, 0, 1 + (week - 1) * 7)); const day = d.getUTCDay(); // 调整到周一(UTC周日是0,所以周日要减6天,其他情况减到周一) const diff = day === 0 ? -6 : 1 - day; d.setUTCDate(d.getUTCDate() + diff); return d; } // 根据日期获取对应的ISO年份和周数 function getYearWeek(date) { const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate())); const dayNum = d.getUTCDay() || 7; // 把周日转为7 d.setUTCDate(d.getUTCDate() + 4 - dayNum); // 转到该周的周四,确保年份正确 const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1)); const weekNo = Math.ceil((((d - yearStart) / 86400000) + 1) / 7); return { reportYear: d.getUTCFullYear(), reportWeek: weekNo }; }
主补全函数
function fillMissingWeeks(data) { if (data.length === 0) return []; // 1. 排序并确定时间范围(最早和最晚的周) const sortedData = [...data].sort((a, b) => { const aKey = a.reportYear * 100 + a.reportWeek; const bKey = b.reportYear * 100 + b.reportWeek; return aKey - bKey; }); const startWeek = sortedData[0]; const endWeek = sortedData[sortedData.length - 1]; // 2. 生成完整的周序列 const fullWeekList = []; let currentDate = getDateOfWeek(startWeek.reportYear, startWeek.reportWeek); const endDate = getDateOfWeek(endWeek.reportYear, endWeek.reportWeek); while (currentDate <= endDate) { fullWeekList.push(getYearWeek(currentDate)); // 每周加7天,推进到下一周 currentDate.setUTCDate(currentDate.getUTCDate() + 7); } // 3. 把原数据转成Map,用`年份-周数`作为键,快速查找 const existingWeekMap = new Map(); data.forEach(item => { const key = `${item.reportYear}-${item.reportWeek}`; existingWeekMap.set(key, {...item}); // 存副本避免修改原数据 }); // 4. 补全缺失的周 const result = fullWeekList.map(yw => { const key = `${yw.reportYear}-${yw.reportWeek}`; if (existingWeekMap.has(key)) { return existingWeekMap.get(key); } else { // 复用第一个数据项的固定属性,缺失的数值设为0(可根据需求改null/undefined) const template = sortedData[0]; return { ...template, reportYear: yw.reportYear, reportWeek: yw.reportWeek, importanceDegree: 0 }; } }); return result; }
多员工场景扩展
如果你的数据包含多个员工,只需要先按employeeCode分组,再对每个员工单独补全:
function fillMissingWeeksByEmployee(data) { // 按员工编码分组 const employeeGroups = {}; data.forEach(item => { const key = item.employeeCode; if (!employeeGroups[key]) employeeGroups[key] = []; employeeGroups[key].push(item); }); // 对每个员工组补全周数,合并结果 const finalResult = []; Object.values(employeeGroups).forEach(group => { finalResult.push(...fillMissingWeeks(group)); }); return finalResult; }
使用示例
// 你的示例输入 const inputData = [ {"reportYear":2017,"reportWeek":49,"employeeCode":100,"employeeName":"Peter","importanceDegree":182.0}, {"reportYear":2017,"reportWeek":52,"employeeCode":100,"employeeName":"Peter","importanceDegree":77.0}, {"reportYear":2018,"reportWeek":2,"employeeCode":100,"employeeName":"Peter","importanceDegree":90.0} ]; // 补全后的数据 const filledData = fillMissingWeeks(inputData); console.log(filledData);
运行后会得到包含2017周49-52、2018周1-2的完整数据,其中缺失的周(2017周50、51,2018周1)的importanceDegree会被设为0。
注意事项
- 周定义调整:如果你的业务中周是从周日开始,需要修改辅助函数里的日期调整逻辑。
- 默认值设置:缺失周的数值字段(比如
importanceDegree)可以根据需求改成null、undefined或者其他默认值。 - 数据验证:如果原数据中存在同一员工同一周的多条数据,建议先做去重处理,避免Map覆盖问题。
内容的提问来源于stack exchange,提问作者user9270170
相关产品推荐
相关产品推荐

