JavaScript数组修改:如何按指定起止年份补全缺失的年份统计对象
高效补全缺失年份的实现方案
你目前用的双重循环方式(遍历目标年份区间,每次循环都全量扫描原数组校验年份是否存在),整体时间复杂度为 O(区间年份总数 * 原数组长度),当年份跨度大、原数据量多时,会产生大量无意义的遍历操作,性能和可读性都比较差。
优化的核心思路是把存在性校验的时间复杂度从O(n)降到O(1),减少无意义的重复遍历,整体实现逻辑如下:
实现步骤
- 构建快速查找索引
仅遍历一次原数组,将其转换成以数字格式年份为键的Map对象,同时过滤掉不在目标起止区间内的无效数据。后续判断某个年份是否存在时,直接从Map中取值即可,查找操作的时间复杂度为O(1)。 - 按区间生成全量结果
从给定的起始年份开始,逐年迭代到结束年份:- 若当前年份能在Map中找到对应原数据,直接把原对象推入结果数组
- 若找不到,直接推入格式为
{year: 当前年份字符串, count: 0}的补全对象
- 天然有序的结果输出
因为迭代过程是从起始年份到结束年份逐年后推的,最终生成的结果数组天然就是按年份升序排列的,不需要额外执行排序操作。
代码示例
// 原始数据 const rawData = [ {year: "1920", count: 0}, {year: "1921", count: 2}, {year: "1925", count: 0}, {year: "1930", count: 21} ] // 定义补全的年份区间 const startYear = 1900 const endYear = 2000 // 第一步:构建年份到原数据的映射,同时过滤不在区间内的无效数据 const yearIndex = new Map() rawData.forEach(item => { const yearNum = Number(item.year) if (yearNum >= startYear && yearNum <= endYear) { yearIndex.set(yearNum, item) } }) // 第二步:逐年份生成补全后的数组 const filledResult = [] for (let y = startYear; y <= endYear; y++) { const existedItem = yearIndex.get(y) if (existedItem) { filledResult.push(existedItem) } else { filledResult.push({ year: String(y), count: 0 }) } }
方案优势
- 整体时间复杂度为
O(原数组长度 + 区间年份总数),相比原双重循环实现,性能优势会随数据量增长被进一步拉大:比如原数组长度1万、区间跨度1000年的场景下,原实现需要千万次级别的查找操作,这个实现仅需万次级别的操作,性能差两个数量级 - 逻辑链路清晰,不需要维护“已存在年份”这类临时去重状态,代码维护成本低
- 结果天然有序,省去了最后全量排序的额外开销
补充:如果原数组已经是按年份升序排列、且数据量极大到存Map会占用过多内存的场景,可以改用双指针合并的方式实现,空间复杂度可以降到O(1),不过这种方式对原数组的顺序有硬性要求,通用性不如Map索引的方案。
内容的提问来源于stack exchange,提问作者alp123
相关产品推荐
相关产品推荐

