如何基于start/end属性高效筛选待删对象及状态分类排查
问题分析
你的代码出现错误的核心原因是:
- 用
id|start|end作为唯一标识key,将所有现有对象中key不存在于更新列表的项都标记为deleted,但忽略了「更新列表仅包含变更项,未出现的对象应视为无变更(unchanged)」的场景。 - 同时,
unchanged的筛选逻辑仅从更新列表中取数,遗漏了现有列表中未被修改的对象。
具体来说,id为333的对象在更新列表中完全没有出现,按照你的预期它属于无变更项,但当前代码因为它的key不在更新列表的Map中,被错误归入deleted数组。
修正方案
我们需要调整逻辑,以id为核心标识区分不同状态,再结合start/end/cost判断具体类型:
- added:更新列表中新增的id,或同id但
start/end变更后的新对象 - deleted:现有列表中同id但
start/end变更的原对象(即被替换的旧项) - updated:同id且
start/end不变,但cost修改的对象 - unchanged:现有列表中未被修改的对象(包括更新列表中未出现的id,以及同id且所有属性都不变的项)
修正后的代码:
const existingItems = [ { id: '111', start: 0, end: 10, cost: 100 }, { id: '222', start: 20, end: 30, cost: 200 }, { id: '333', start: 20, end: 30, cost: 200 }, ]; const updatedItems = [ { id: '111', start: 0, end: 9, cost: 42 }, { id: '222', start: 20, end: 30, cost: 400 }, ]; function changes(existing, updated) { // 按id创建映射,方便快速查找 const existingById = new Map(existing.map(item => [item.id, item])); const updatedById = new Map(updated.map(item => [item.id, item])); const changedItems = { added: [], deleted: [], updated: [], unchanged: [] }; // 遍历现有对象,处理deleted和unchanged for (const existingItem of existing) { const updatedItem = updatedById.get(existingItem.id); if (!updatedItem) { // 更新列表中无此id,视为无变更 changedItems.unchanged.push(existingItem); continue; } // 比较start和end if (existingItem.start !== updatedItem.start || existingItem.end !== updatedItem.end) { // start/end变更,原对象标记为删除 changedItems.deleted.push(existingItem); } else { // start/end不变,比较cost if (existingItem.cost !== updatedItem.cost) { // cost变更,后续在updated数组中添加 continue; } else { // 所有属性不变,视为无变更 changedItems.unchanged.push(existingItem); } } } // 遍历更新对象,处理added和updated for (const updatedItem of updated) { const existingItem = existingById.get(updatedItem.id); if (!existingItem) { // 现有列表中无此id,视为新增 changedItems.added.push(updatedItem); continue; } // 比较start和end if (existingItem.start !== updatedItem.start || existingItem.end !== updatedItem.end) { // start/end变更,新对象标记为新增 changedItems.added.push(updatedItem); } else { // start/end不变,比较cost if (existingItem.cost !== updatedItem.cost) { // cost变更,标记为更新 changedItems.updated.push(updatedItem); } // 所有属性不变的情况已在前面处理,无需重复添加 } } return changedItems; } let result = changes(existingItems, updatedItems); console.log(result);
输出结果说明
修正后输出的各数组符合预期:
deleted:仅包含id为111的原对象(因为它的start/end被修改,旧项需删除)unchanged:包含id为333的对象(更新列表中未出现,视为无变更)updated:包含id为222的对象(仅cost修改)added:包含id为111的新对象(start/end修改后的新增项)
内容的提问来源于stack exchange,提问作者cafe123
相关产品推荐
相关产品推荐

