去重的核心:要根据实际业务怎么定义'重'
基本数据类型
js
const arr = [1, 2, 1, 3];
//用Set去重
const uniqueArr = [...new Set(arr)]; // [1, 2, 3]
//用filter去重
const uniqueArr = arr => arr.filter((item, index) => arr.indexOf(item) === index); // 相同的元素只保留一个
//indexOf
const uniqueArr = (arr) =>{
let newArr = [];
for (let i = 0; i < arr.length; i++) {
if (newArr.indexOf(arr[i]) === -1) {//或 !newArr.includes(arr[i])
newArr.push(arr[i]);
}
}
return newArr;
}
//==> reduce与 includes
const uniqueArr = (arr) => arr.reduce((newArr,item) => newArr.includes(item) ? newArr : [...newArr,item],[])
//双重循环遍历数组去重
const arr = [1, 2, 2, 3, 3, 3];
const uniqueArr = [];
for (let i = 0; i < arr.length; i++) {
let isDuplicate = false;
for (let j = 0; j < uniqueArr.length; j++) {
if (arr[i] === uniqueArr[j]) {
isDuplicate = true;
break;
}
}
if (!isDuplicate) {
uniqueArr.push(arr[i]);
}
}
console.log(uniqueArr); // [1, 2, 3]
如果要去重一个包含不同数据类型的数组,需要添加一些额外的检查。
Date类型转换成Unix时间戳,RegExp类型转换成字符串。
js
const arr = ['a', 'b', 1, 1, 'a', /abc/, /abc/, new Date(), new Date()]
const isObject = val => Object(val) === val// 判断是否为对象
function uniqueArr(arr) {
return [...new Set(arr.map((item) => {
if (!isObject(item))
return item // 不是
if (item instanceof Date)
return item.getTime()
else if (item instanceof RegExp)
return item.toString()
}))]
}
uniqueArr(arr) // ['a', 'b', 1, '/abc/', 1678519417983]
对象数组去重
对象相同比较
基本思路:
- 首先判断两个值的类型是否相同,如果不同,则返回
false
; - 处理特殊情况
null、undefined、Date、function
; - 处理数组类型,对比项的数量,再递归对比每个项是否相等;
- 处理朴素对象,对比键的数量,相等则再递归对比值是否相等。
js
function isEqual(obj1, obj2) {
const equalType = (val1, val2) => Object.prototype.toString.call(val1) !== Object.prototype.toString.call(val2)
// 判断类型是否一致
if (equalType(obj1, obj2)) {
return false
}
// 判断 null 和 undefined:只要有一个为 null 或 undefined,则直接比较值
if (obj1 === null || obj2 === null || obj1 === undefined || obj2 === undefined) {
return obj1 === obj2
}
// 判断基本类型是否相等
if (typeof obj1 === 'number' || typeof obj1 === 'string' || typeof obj1 === 'boolean') {
return obj1 === obj2
}
if (typeof obj1 === 'function' && typeof obj2 === 'function')
return obj1.toString() === obj2.toString()
if (obj1 instanceof Date && obj2 instanceof Date)
return obj1.getTime() === obj2.getTime()
// 判断数组是否相等
if (Array.isArray(obj1)) {
if (!Array.isArray(obj2) || obj1.length !== obj2.length) {
return false
}
return obj1.every((item, index) => isEqual(item, obj2[index]))
// for (let i = 0; i < obj1.length; i++) {
// if (!isEqual(obj1[i], obj2[i])) {
// return false;
// }
// }
// return true;
}
// 比较对象是否相等
// Object.keys: 返回对象自身的所有可枚举的属性的键名,不包含 Symbol 类型键名
// Reflect.ownKeys(): 返回所有类型的键名,包括常规键名和 Symbol 键名。
const keys1 = Object.keys(obj1)
const keys2 = Object.keys(obj2)
if (keys1.length !== keys2.length) {
return false
}
for (const key of keys1) {
if (!isEqual(obj1[key], obj2[key])) {
return false
}
}
return true
}
测试示例
js
// 示例
const obj1 = {
name: 'Tom',
age: 18,
hobby: ['reading', 'music'],
address: {
province: 'Guangdong',
city: 'Shenzhen',
detail: {
street: 'Xinxi Road',
number: 888
},
date: new Date('2022-02-13'),
func() {
console.log(1)
}
}
}
const obj2 = {
name: 'Tom',
age: 18,
hobby: ['reading', 'music'],
address: {
province: 'Guangdong',
city: 'Shenzhen',
detail: {
street: 'Xinxi Road',
number: 888
},
date: new Date('2022-02-13'),
func() {
console.log(1)
}
}
}
const obj3 = {
name: 'Tom',
age: 18,
hobby: ['reading', 'music', 'dance'],
address: {
province: 'Guangdong',
city: 'Shenzhen',
detail: {
street: 'Xinxi Road',
number: 888
},
// date:new Date('2022-02-13'),
// func:function(){
// console.log(1)
// }
}
}
isEqual(obj1, obj2) // true
isEqual(obj1, obj3) // false
isEqual(undefined, null)// false
isEqual(null, null)
对象数组去重
js
const arr = [1,2,3,1]
//深拷贝
function deepClone(obj){
if(obj === null || typeof obj !== 'object') return obj
if(obj.constructor === Date) return new Date(obj);
if(obj.constructor === RegExp) return new RegExp(obj);
let newObj = Array.isArray(obj) ? [] : {}
for(let key in obj){
if(obj.hasOwnProperty(key)) newObj[key] = deepClone(obj[key])
}
return newObj
}
const uniqueArr(arr){
const newArr = deepClone(arr)
let len = newArr.length
for(let i = 0; i < len; i++){
for(let j = i + 1; j < len; j++){
if(isEqual(newArr[i], newArr[j])){
newArr.splice(j,1)
}
}
}
return newArr
}
测试数据
js
const objArr1 = [
{ a: 1, b: 2 },
{ a: 2, b: 3 },
{ b: 2, a: 1 },
{ a: 3, b: 2 },
[1, 2, 3],
[4, 5, 6],
[2, 1, 3],
{
name: 'Tom',
age: 18,
hobby: ['reading', 'music'],
address: {
province: 'Guangdong',
city: 'Shenzhen',
detail: {
street: 'Xinxi Road',
number: 888
},
date: new Date('2022-02-13'),
func() {
console.log(1)
}
}
},
{
name: 'Tom',
age: 18,
hobby: ['reading', 'music'],
address: {
province: 'Guangdong',
city: 'Shenzhen',
detail: {
street: 'Xinxi Road',
number: 888
},
date: new Date('2022-02-13'),
func() {
console.log(1)
}
}
},
{
name: 'Tom',
age: 18,
hobby: ['reading', 'music', 'dance'],
address: {
province: 'Guangdong',
city: 'Shenzhen',
detail: {
street: 'Xinxi Road',
number: 888
},
// date:new Date('2022-02-13'),
// func:function(){
// console.log(1)
// }
}
},
{
name: 'Tom',
age: 18,
hobby: ['reading', 'music', 'dance'],
address: {
province: 'Guangdong',
city: 'Shenzhen',
detail: {
street: 'Xinxi Road',
number: 888
},
date: new Date('2022-02-13'),
func() {
console.log(2)
}
}
},
{
name: 'Tom',
age: 18,
hobby: ['reading', 'music', 'dance'],
address: {
province: 'Guangdong',
city: 'Shenzhen',
detail: {
street: 'Xinxi Road',
number: 888
},
date: new Date('2022-02-11'),
func() {
console.log(2)
}
}
}
]
// uniqueArr(objArr1)