列表间移动数字时如何高效重新计算range区间
方案思路
直接操作区间对象完成增删改,无需展开大区间的全量数字,仅需要对要移动的少量数字做区间转换,内存占用和性能都远优于原方案,同时兼容你现有的数字列表输入格式。
执行步骤
步骤1:将要移动的数字转为连续区间
即使输入是零散数字列表,也仅需要用你现有getRanges函数对这部分小数据做区间转换:
// 比如要移动的数字是[5000010,5000011,...5000020],直接转成区间 const moveRanges = getRanges(moveNumbers)
这一步处理的是你要移动的少量数字,完全不存在内存占用问题。
步骤2:更新移出列表的区间
遍历移出列表的原有区间,和moveRanges中的每一段做比对,只保留未被移出的部分:
function removeRanges(originalRanges, removeRanges) { let result = [...originalRanges] for (const rm of removeRanges) { const newResult = [] for (const ori of result) { // 完全不重叠:直接保留 if (ori.upper < rm.lower || ori.lower > rm.upper) { newResult.push(ori) continue } // 移出区间覆盖头部:保留尾部 if (ori.lower < rm.lower && ori.upper <= rm.upper) { newResult.push({ lower: ori.lower, upper: rm.lower - 1 }) } // 移出区间覆盖尾部:保留头部 else if (ori.lower >= rm.lower && ori.upper > rm.upper) { newResult.push({ lower: rm.upper + 1, upper: ori.upper }) } // 移出区间切在中间:拆成两段保留 else if (ori.lower < rm.lower && ori.upper > rm.upper) { newResult.push({ lower: ori.lower, upper: rm.lower - 1 }) newResult.push({ lower: rm.upper + 1, upper: ori.upper }) } // 完全覆盖:直接丢弃,不用加 } result = newResult } // 按lower升序排序 return result.sort((a, b) => a.lower - b.lower) }
步骤3:更新移入列表的区间
把要移动的区间加入移入列表后,做一次相邻区间合并即可:
function addRanges(originalRanges, addRanges) { // 合并所有区间后排序 const allRanges = [...originalRanges, ...addRanges].sort((a, b) => a.lower - b.lower) if (allRanges.length === 0) return [] const merged = [allRanges[0]] for (let i = 1; i < allRanges.length; i++) { const current = allRanges[i] const last = merged[merged.length - 1] // 相邻区间连续则合并 if (current.lower === last.upper + 1) { last.upper = current.upper } else { merged.push(current) } } return merged }
示例验证
以你给出的从C列表移动5000010到5000020到B列表为例:
- 转换移动数字得到
moveRanges = [{lower:5000010, upper:5000020}] - 调用
removeRanges(C的原有区间, moveRanges),得到处理后的C区间:
[ {lower:5000001, upper:5000009}, {lower:5000021, upper:6999900}, {lower:9000000, upper:9999999} ]
- 调用
addRanges(B的原有区间, moveRanges),得到处理后的B区间:
[ {lower:13, upper:15}, {lower:21,upper:30}, {lower:34,upper:9999}, {lower:5000010, upper:5000020} ]
和你预期的结果完全一致,全程没有展开任何大区间,仅处理了少量的区间对象。
内容的提问来源于stack exchange,提问作者Tania
相关产品推荐
相关产品推荐

