在TypeScript的实际开发中,我们经常会遇到需要对比两个对象数组,找到第一个不与另一个数组ID重复的唯一对象的需求,比如从候选列表中排除已经被选中的元素,获取第一个可用的候选对象。

需求场景说明
假设我们有两个对象数组,第一个数组是候选对象列表,每个对象都包含唯一的id属性;第二个数组是已经被选中的对象列表,同样包含id属性。我们需要从候选列表中找到第一个id不在已选中列表中的对象,作为本次要选中的目标。
基础实现方案
最直观的实现方式是先遍历已选中数组,收集所有已存在的id,再遍历候选数组找到第一个id不在已收集集合中的对象,这种方式可以避免嵌套循环,提升查找效率。
// 定义对象类型,包含id属性
interface Item {
id: number;
name: string;
}
// 候选对象数组
const candidateList: Item[] = [
{ id: 1, name: '对象1' },
{ id: 2, name: '对象2' },
{ id: 3, name: '对象3' },
{ id: 4, name: '对象4' },
];
// 已选中对象数组
const selectedList: Item[] = [
{ id: 2, name: '对象2' },
{ id: 4, name: '对象4' },
];
// 提取已选中对象的id集合
const selectedIdSet = new Set(selectedList.map(item => item.id));
// 查找第一个不与已选中数组ID重复的对象
const targetItem = candidateList.find(item => !selectedIdSet.has(item.id));
console.log(targetItem); // 输出: { id: 1, name: '对象1' }
封装为通用函数
为了复用这个逻辑,我们可以将其封装为一个通用的TypeScript函数,支持自定义id的键名,适配不同的对象结构。
// 通用查找函数,key为id对应的属性名,默认是'id'
function findFirstUniqueItem<T extends Record<string, any>>(
candidateArr: T[],
selectedArr: T[],
key: string = 'id'
): T | undefined {
// 收集已选中数组的key值集合
const selectedKeySet = new Set(selectedArr.map(item => item[key]));
// 查找第一个key值不在集合中的候选对象
return candidateArr.find(item => !selectedKeySet.has(item[key]));
}
// 测试自定义键名的情况
interface User {
userId: number;
username: string;
}
const userCandidates: User[] = [
{ userId: 101, username: '张三' },
{ userId: 102, username: '李四' },
{ userId: 103, username: '王五' },
];
const selectedUsers: User[] = [
{ userId: 102, username: '李四' },
];
const firstUniqueUser = findFirstUniqueItem(userCandidates, selectedUsers, 'userId');
console.log(firstUniqueUser); // 输出: { userId: 101, username: '张三' }
边界情况处理
在实际使用中,我们需要考虑一些边界场景,比如候选数组为空、已选中数组为空、所有候选对象都已被选中的情况,通用函数已经做了兼容,当没有找到符合条件的对象时会返回undefined,使用时可以做对应的判断。
// 所有候选对象都已被选中的情况
const allSelectedCandidates: Item[] = [
{ id: 2, name: '对象2' },
{ id: 4, name: '对象4' },
];
const result = findFirstUniqueItem(allSelectedCandidates, selectedList);
console.log(result); // 输出: undefined
// 已选中数组为空的情况
const emptySelected: Item[] = [];
const result2 = findFirstUniqueItem(candidateList, emptySelected);
console.log(result2); // 输出: { id: 1, name: '对象1' }
性能对比
如果使用嵌套循环的方式实现,时间复杂度是O(n*m),n是候选数组长度,m是已选中数组长度;而使用Set的方式,时间复杂度是O(n+m),在数据量较大时性能优势会非常明显。以下是两种方式的简单对比:
| 实现方式 | 时间复杂度 | 适用场景 |
|---|---|---|
| 嵌套循环遍历 | O(n*m) | 数据量极小的场景 |
| Set+find方法 | O(n+m) | 大部分常规场景,尤其是数据量较大的情况 |
总结
通过Set收集已选中对象的ID,再结合数组的find方法查找第一个不重复的对象,是TypeScript中实现该需求的高效方式。这种方式代码简洁,性能表现好,还可以通过封装通用函数适配不同的业务场景,开发者可以根据实际需求灵活调整使用。
TypeScript数组去重对象查找ID匹配修改时间:2026-07-12 00:06:34