Skip to content

去重的核心:要根据实际业务怎么定义'重'

基本数据类型

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;//判断是否为对象
const uniqueArr = (arr) =>[...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]

对象数组去重

对象相同比较

基本思路

  1. 首先判断两个值的类型是否相同,如果不同,则返回 false
  2. 处理特殊情况 null、undefined、Date、function
  3. 处理数组类型,对比项的数量,再递归对比每个项是否相等;
  4. 处理朴素对象,对比键的数量,相等则再递归对比值是否相等。
javascript
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;
}

:::details 测试示例

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:function(){
      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:function(){
      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
}

:::details 测试数据

js
let 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:function(){
      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: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: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:function(){
     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:function(){
     console.log(2)
    }
  }
}
]
//uniqueArr(objArr1)

:::

用心去做高质量的内容网站,欢迎 star ⭐ 让更多人发现