处理数组重复可能会很棘手
进一步阅读
原帖发布于我的博客。查看更多最新内容
让我们首先定义一个简单的数组:
const cars = [
'Mazda',
'Ford',
'Renault',
'Opel',
'Mazda'
]
如您所见,第一个元素和最后一个元素是相同的。考虑到我们有一个原始类型的数组,查找这个重复元素非常简单。为了实现这一点,我们可以简单地在提供的回调函数中filter
结合使用 和indexOf
。
const unique = cars.filter((car, idx) => cars.indexOf(car) === idx);
console.log(unique); // outputs ['Mazda', 'Ford', 'Renault', 'Opel']
请注意,该indexOf
方法将返回数组中某个元素的第一次出现。因此,我们可以indexOf
在每次迭代中将该方法返回的索引与当前索引进行比较,以判断当前元素是否重复。
查找对象重复项
这部分比较棘手。对象是通过引用而不是值或结构体进行比较的。这意味着,如果我们比较两个完全相同的对象,它们将不会匹配。我们不能仅仅obj1 === obj2
因为它们的比较方式而做出类似的操作。
const obj1 = {
name: 'John',
surname: 'Doe'
}
const obj2 = {
name: 'John',
surname: 'Doe'
}
const match = obj1 === obj2;
console.log(match) // outputs false
现在,如果我们有一个对象重复的数组怎么办?我们该如何过滤掉它们?考虑到我们刚刚读到的内容,不可能使用像 这样的简单方法indexOf
。
示例数组:
const names = [{
name: 'John',
surname: 'Doe'
}, {
name: 'Muhamed',
surname: 'Ali'
}, {
name: 'Mike',
surname: 'Tyson'
}, {
name: 'John',
surname: 'Doe'
}, {
name: 'John',
surname: 'Doe'
}, {
name: 'Mike',
surname: 'Tyson'
}, {
name: 'Mike',
surname: 'Tyson'
}];
如你所见,我们有几个重复的项目。让我们实现查找重复项的函数。
更长的版本
在这种方法中,我们将手动循环遍历源数组(forEach
方法),并使用该find
方法检查每个项目是否存在于结果数组中。
考虑到我们有一个对象数组,我们必须比较当前对象的每个属性,以确保项目相同。该过程分解为几个步骤,如下所示:
- 获取对象属性
- 定义结果数组(
unique
和duplicates
) - 循环遍历源数组
unique
尝试在数组中找到当前项- 如果找到该项目,则将其推入数组,
duplicates
否则将其推入unique
数组
const findDuplicates = (source) => {
const keys = Object.keys(source[0]);
let unique = [], duplicates = [];
source.forEach((item, idx) => {
if(idx == 0) {
unique.push(item);
return;
};
const resultItem = unique.find(resultItem => {
let notFound = true;
keys.forEach(key => {
notFound = notFound &&
item[key] != resultItem[key];
});
return !notFound;
});
(!resultItem ? unique : duplicates).push(item);
});
return { unique: unique, duplicates: duplicates };
};
const result = findDuplicates(names);
console.log(result.unique, result.duplicates);
// expected output
// unique items
// 0: {name: "John", surname: "Doe"}
// 1: {name: "Muhamed", surname: "Ali"}
// 2: {name: "Mike", surname: "Tyson"}
// duplicate items
// 0: {name: "John", surname: "Doe"}
// 1: {name: "John", surname: "Doe"}
// 2: {name: "Mike", surname: "Tyson"}
// 3: {name: "Mike", surname: "Tyson"}
稍短版本
我们可以使用该reduce
方法来实现相同的目的。这是一个非常强大的方法,可以将数组转换为所需的结果。它接受一个回调函数作为参数,该回调函数会针对数组中的每个元素执行一次。回调函数的返回值是每次迭代中修改后的给定累加器。鉴于本文并非专门介绍该reduce
方法的文章,请参阅官方MDN 文档。
好的,回到我们的代码。该findDuplicates
方法的修改版本如下所示:
const findDuplicates = (source) => {
const keys = Object.keys(source[0]);
return source.reduce((acc, item) => {
const resultItem = acc.unique.find(x => {
let notFound = true;
keys.forEach(key => {
notFound = notFound &&
item[key] != x[key];
});
return !notFound;
});
(!resultItem ? acc.unique : acc.duplicates).push(item);
return acc;
}, {
unique: [],
duplicates: []
})
};
修改后的版本应该返回与以前相同的结果数组。
// unique items
// 0: {name: "John", surname: "Doe"}
// 1: {name: "Muhamed", surname: "Ali"}
// 2: {name: "Mike", surname: "Tyson"}
// duplicate items
// 0: {name: "John", surname: "Doe"}
// 1: {name: "John", surname: "Doe"}
// 2: {name: "Mike", surname: "Tyson"}
// 3: {name: "Mike", surname: "Tyson"}
就这样吧。感谢您的阅读,我们下篇文章再见。
进一步阅读
请参阅此备忘单,它将指导您了解数组操作时最常见的用例。
文章来源:https://dev.to/proticm/handling-array-duplicates-can-be-tricky-4ob0