基于Id移除对象数组中除指定disciplineId外的重复项
解决方案
方法一:用reduce+Map去重(推荐,逻辑清晰)
直接通过生成唯一标识键的方式,对除disciplineId外属性相同的对象组,只保留你指定disciplineId的对象。
假设你要保留的目标disciplineId为targetDisciplineId(比如示例中的2f33be5c-f3fa-4c50-3bda-08dac6565a75),代码如下:
const targetDisciplineId = "2f33be5c-f3fa-4c50-3bda-08dac6565a75"; const filteredSchedules = Array.from( schedulesList.reduce((map, item) => { // 生成唯一键:用除disciplineId外的核心属性拼接(code、description、id足够区分重复组) const uniqueKey = `${item.code}-${item.description}-${item.id}`; // 规则:键不存在则直接存入;键已存在但当前item是目标disciplineId,替换原有值(确保保留目标项) if (!map.has(uniqueKey) || item.disciplineId === targetDisciplineId) { map.set(uniqueKey, item); } return map; }, new Map()).values() );
方法二:修复你的移除逻辑
如果你坚持用splice实现删除,需要解决原代码的三个问题:
splice必须传入第二个参数(删除数量),否则会删除从当前索引到数组末尾的所有元素;- 倒序循环数组,避免删除元素后索引错乱导致漏删;
- 对比对象时不能依赖
indexOf(引用类型匹配问题),改用属性值精准匹配。
代码示例:
const targetDisciplineId = "2f33be5c-f3fa-4c50-3bda-08dac6565a75"; // 先定位所有需要删除的对象:重复组中非目标disciplineId的项 const itemsToRemove = schedulesList.filter(item => { // 找到同组的所有对象 const sameGroup = schedulesList.filter(i => i.code === item.code && i.description === item.description && i.id === item.id ); // 同组有多个对象,且当前项不是目标disciplineId return sameGroup.length > 1 && item.disciplineId !== targetDisciplineId; }); // 倒序循环删除,避免索引偏移 for (let i = itemsToRemove.length - 1; i >= 0; i--) { const removeItem = itemsToRemove[i]; const index = schedulesList.findIndex(item => item.id === removeItem.id && item.disciplineId === removeItem.disciplineId ); if (index !== -1) { schedulesList.splice(index, 1); // 第二个参数1表示仅删除当前元素 } }
原方法失效的原因
splice(scheduleList.indexOf(schedulesToRemove[i]))缺少第二个参数,默认删除从索引到数组末尾的所有元素,直接打乱后续循环的索引逻辑;- 对象是引用类型,若
schedulesToRemove中的对象和原数组不是同一个引用(比如是复制生成的),indexOf会返回-1,根本无法定位到目标元素; - 正序循环删除元素时,数组长度缩短导致后续元素索引前移,会跳过部分需要删除的项。
内容的提问来源于stack exchange,提问作者lross33
相关产品推荐
相关产品推荐

