在实现数组、对象数组去重之前我们要先来认识一下set
对象。
在JavaScript中,
Set
是一种集合(collection)对象,它允许你存储不重复的值。下面是一个简单的案例,演示如何使用Set
对象:
// 创建一个空的 Set 对象
let mySet = new Set();
// 添加元素到 Set
mySet.add(1);
mySet.add(2);
mySet.add(3);
mySet.add(1); // 这个值将被忽略,因为它是重复的
console.log(mySet); // 输出: Set { 1, 2, 3 }
// 检查 Set 中是否包含某个值
console.log(mySet.has(2)); // 输出: true
console.log(mySet.has(4)); // 输出: false
// 获取 Set 中的元素数量
console.log(mySet.size); // 输出: 3
// 删除 Set 中的元素
mySet.delete(2);
console.log(mySet); // 输出: Set { 1, 3 }
// 迭代 Set 中的元素
mySet.forEach(value => {
console.log(value);
});
// 输出:
// 1
// 3
在这个例子中,mySet
是一个 Set
对象,通过 add
方法添加了一些元素,注意添加重复元素时会被忽略。使用 has
方法检查值是否存在,使用 size
获取元素数量,使用 delete
方法删除元素,最后使用 forEach
迭代集合中的每个元素。Set
的特性在实现去重、集合操作等方面非常有用。
当你需要从一个数组中去除重复的元素时,Set
是一个非常方便的工具。以下是一个利用 Set
去重的案例:
// 一个包含重复元素的数组
let arrayWithDuplicates = [1, 2, 3, 1, 2, 4];
// 使用 Set 去重
let uniqueArray = [...new Set(arrayWithDuplicates)];
console.log(uniqueArray);
// 输出: [1, 2, 3, 4]
在这个例子中,new Set(arrayWithDuplicates)
会创建一个包含数组中唯一值的 Set
对象。然后,通过使用展开运算符 ...
将 Set
转换为数组,最终得到 uniqueArray
,它包含了原始数组中的唯一值,去除了重复项。
从官方文档中可以明显看出,在 set
对象中进行去重是通过严格相等。因此对于对象数组,直接如上使用set
就不合适了。
利用set去重的代码就相当于:
let arrayWithDuplicates = [1, 2, 3, 1, 2, 4];
// 去重数组
function deduplicateArray(array) {
let uniqueArray = [];
for (let i = 0; i < array.length; i++) {
let isDuplicate = false;
for (let j = 0; j < uniqueArray.length; j++) {
if (array[i] === uniqueArray[j]) {
isDuplicate = true;
break;
}
}
if (!isDuplicate) {
uniqueArray.push(array[i]);
}
}
return uniqueArray;
}
let deduplicatedArray = deduplicateArray(arrayWithDuplicates);
console.log(deduplicatedArray);
// 输出: [1, 2, 3, 4]
这个函数 deduplicateArray
遍历原始数组,并将每个元素与结果数组中的元素比较。如果没有找到重复项,就将当前元素添加到结果数组中。请注意,这个方法的时间复杂度较高,特别是在数组较大的情况下。
不能直接使用 set
进行对象数组去重就是因为 array[i] === uniqueArray[j]
全等于和我们认为理解的对象相等含义不一样,所以只要我们进一步改写这里的相等算法,来比较两个对象是否相等,就可以实现对象数组去重了。
因此我们进一步把array[i] === uniqueArray[j]
改写为一个判断对象相等的equal
方法,判断对象是否相等也适用,使用递归进行比较。
// 判断是不是对象
const isObject = (val) => typeof val === 'object' && val !== null
// 自定义 equal 方法
function equal (val1, val2) {
if (isObject(val1) && isObject(val2)) {
const keys1 = Object.keys(val1)
const keys2 = Object.keys(val2)
// 如果两个对象的 key 都不相同,那肯定是不相同的
if (keys1.length !== keys2.length) {
return false
}
for (const key of keys1) {
// 如果 val2 中都没有这个属性,那肯定也不相同
if (!keys2.includes(key)) {
return false
}
if (!equal(val1[key], val2[key])) {
return false
}
}
// 上述比较后没有发现什么不一样的地方,那么就说明是相同的
return true
} else {
return val1 === val2
}
}
let arrayOfObjects = [
{ id: 1, name: 'John' },
{ id: 2, name: 'Jane' },
{ id: 2, name: 'Jane' }, // 重复的对象
{ name: 'John', id: 1 }, // 重复的对象
{ id: 1, name: 'Kate' },
{ id: 3, name: 'Doe' }
];
// 判断是不是对象
const isObject = (val) => typeof val === 'object' && val !== null
// 自定义 equal 方法
function equal (val1, val2) {
if (isObject(val1) && isObject(val2)) {
const keys1 = Object.keys(val1)
const keys2 = Object.keys(val2)
// 如果两个对象的 key 都不相同,那肯定是不相同的
if (keys1.length !== keys2.length) {
return false
}
for (const key of keys1) {
// 如果 val2 中都没有这个属性,那肯定也不相同
if (!keys2.includes(key)) {
return false
}
if (!equal(val1[key], val2[key])) {
return false
}
}
// 上述比较后没有发现什么不一样的地方,那么就说明是相同的
return true
} else {
return val1 === val2
}
}
// 使用双循环和自定义 equal 方法去重对象数组
function deduplicateObjects (array) {
let uniqueObjects = [];
for (let i = 0; i < array.length; i++) {
let isDuplicate = false;
for (let j = 0; j < uniqueObjects.length; j++) {
if (equal(array[i], uniqueObjects[j])) {
isDuplicate = true;
break;
}
}
if (!isDuplicate) {
uniqueObjects.push(array[i]);
}
}
return uniqueObjects;
}
let deduplicatedArray = deduplicateObjects(arrayOfObjects);
console.log(deduplicatedArray);
// 输出 [{"id": 1,"name": "John"},{"id": 2,"name": "Jane"},{"id": 1,"name": "Kate"},{"id": 3,"name": "Doe"}]