假设我们有一个对象数组,如下所示:
const books = [
{
name: “My Sister the Serial Killer”,
author: “Oyinkan Braithwaite”
},
{
name: “Educated”,
author: “Tara Westover”
},
{
name: “My Sister the Serial Killer”,
author: “Oyinkan Braithwaite”
}
];
数组中的第一个和最后一个对象是相同的。那么如果我们想从数组中删除这些重复的对象呢?令人惊讶的是,这是一个非常难以解决的问题。为了理解原因,让我们看一下如何从平面项目数组中删除重复项,例如字符串。
从数组中删除重复的项
假设我们有一个字符串数组,如下所示:
const strings = [
“My Sister the Serial Killer”,
“Educated”,
“My Sister the Serial Killer”
];
如果我们想从这个数组中删除任何重复项,我们可以使用该filter()
方法以及indexOf()
方法来检查任何给定项是否重复。
const filteredStrings = strings.filter((item, index) => {
// Return to new array if the index of the current item is the same
// as the first occurence of the item
return strings.indexOf(item) === index;
});
由于strings.indexOf(item)
将始终返回第一次出现的索引item
,我们可以判断过滤器循环中的当前项是否重复。如果是,我们不会将其返回到由该filter()
方法创建的新数组
对象的工作方式不同
这个方法不适用于对象的原因是因为任何具有相同属性和值的2个对象实际上并不相同。
const a = {
name: “My Sister the Serial Killer”,
author: “Oyinkan Braithwaite”
};
const b = {
name: “My Sister the Serial Killer”,
author: “Oyinkan Braithwaite”
};
a === b // false
这是因为基于参考而不是结构来比较对象。在比较两个对象时,不考虑两个对象具有相同的orperties和value的事实。因此,即使存在具有完全相同属性和值的另一个对象indexOf(object)
,对象数组内也将始终返回精确object
传递的索引。
解决方案
给定此信息,检查两个对象是否具有相同属性和值的唯一方法是实际检查每个对象的属性和值。我提出的解决方案涉及进行此手动检查,但有一些改进性能并减少不必要的嵌套循环。 需要注意3点:
- 仅检查数组中的每个项目与其后的每个其他项目,以避免多次比较相同的对象
- 仅检查未找到与任何其他项目重复的项目
- 在检查每个属性的值是否相同之前,请检查两个对象是否具有相同的键
这是最后的功能:
function removeDuplicates(arr) {
const result = \[\];
const duplicatesIndices = \[\];
// Loop through each item in the original array
arr.forEach((current, index) => {
if (duplicatesIndices.includes(index)) return;
result.push(current);
// Loop through each other item on array after the current one
for (let comparisonIndex = index + 1; comparisonIndex < arr.length; comparisonIndex++) {
const comparison = arr\[comparisonIndex\];
const currentKeys = Object.keys(current);
const comparisonKeys = Object.keys(comparison);
// Check number of keys in objects
if (currentKeys.length !== comparisonKeys.length) continue;
// Check key names
const currentKeysString = currentKeys.sort().join("").toLowerCase();
const comparisonKeysString = comparisonKeys.sort().join("").toLowerCase();
if (currentKeysString !== comparisonKeysString) continue;
// Check values
let valuesEqual = true;
for (let i = 0; i < currentKeys.length; i++) {
const key = currentKeys\[i\];
if ( current\[key\] !== comparison\[key\] ) {
valuesEqual = false;
break;
}
}
if (valuesEqual) duplicatesIndices.push(comparisonIndex);
} // end for loop
}); // end arr.forEach()
return result;
}