论各种操作js数组去重 (附个人深度去重法:见3——针对对象进行强比较去重)

数组去重算是个老生常谈的问题了,不管是面试还是工作都会有所涉及,去重的方法比较多,不好说谁一定好谁一定差,可根据实际需求进行选择。本文列举一些常见的去重方法,并附上方法优劣与适用场合,如有纰漏请指正。

1. 二重循环对比法:

const array = [1, NaN, '1', null, /a/, 1, undefined, null, NaN, '1', {}, /a/, [], undefined, {}, []];
function uniqueByCirculation(arr) {
  const newArr = [];
  let isRepet = false;
    for(let i=0;i < arr.length; i++) {
    for(let j=0;j < newArr.length; j++) {
      if(arr[i] === newArr[j]) {
        isRepet = true;
      }
    };
    if(!isRepet) {
      newArr.push(arr[i]);
    };
  };
  return newArr;
}
const uniquedArr = uniqueByCirculation(array);
console.log(uniquedArr);

结果:这里写图片描述,从结果可以看出Array、Object、RegExp进行了保留,NaN没有去重,原因就涉及到“===”的比较机制了,详情可阅:这里写图片描述
此方法时间复杂度O(NlogN),空间复杂度O(N),适用场合:数据类型简单,数据量少。
2. indexOf法:

const array = [1, NaN, '1', null, /a/, 1, undefined, null, NaN, '1', {}, /a/, [], undefined, {}, []];
function uniqueByIndexOf(arr) {
  return arr.filter((e, i) => arr.indexOf(e) === i);
}
const uniquedArr = uniqueByIndexOf(array);
console.log(uniquedArr);

结果:这里写图片描述
代码简单粗暴,从结果来看,NaN没了,Array、Object、RegExp进行了保留,这是因为Array.indexOf(NaN)总会返回-1,其他复杂类型返回的值总等于自己index,因此得到这样的结果。此方法时间空间复杂度和二重循环一致,适用场合相仿,当然二者相比还是首推这个,毕竟代码短啊。
3. Object[key]法: (个人深度加强版)

const array = [1, '1', NaN, 1, '1',NaN, -0, +0, 0, null, /a/, null, /a/, [], {}, [], {}, [1,2,[2,3]], [1,2,[2,3]], [1,2,[3,2]], undefined,
  {a:1,b:[1,2]}, undefined, {b:[2,1],a:1}, [{a:1},2], [2,{a:1}], {a:{b:1,d:{c:2,a:3},c:1},c:1,d:{f:1,b:2}}, {a:{b:1,d:{c:2,a:3},c:1},c:1,d:{f:1,b:2}}];
function uniqueByObjectKey(arr) {
  const obj = Object.create(null); // 略微优化内存
  const newArr = [];
  let key = '';
  arr.forEach(e => {
    if(isNumberOrString(e)) { // 针对number与string和某些不适合当key的元素进行优化
      key = e + typeof e;
    }else {
      if(e&&isObject(e)){  // 解决同key同value对象的去重
        e = depthSortObject(e);
      }
      key = JSON.stringify(e) + String(e); //JSON.stringify(e)为了应对数组或对象有子内容,String(e)为了区分正则和空对象{}
    }
    if(!obj[key]) {
      obj[key] = key;
      newArr.push(e);
    }
  });
  return newArr;
}
// 判断是否为字符串或数字
function isNumberOrString(e){
  return typeof e === 'number' || typeof e === 'string';
}
// 判断是否为对象
function isObject(e){
  return e.constructor === Object;
}
// 深度排序对象
function depthSortObject(obj){
    if(obj.constructor !== Object){
      return;
    }
    const newobj = {};
    for(const i in obj){
        newobj[i] = obj[i].constructor === Object ? 
        sortObject(depthSortObject(obj[i])) : obj[i]; 
    } 
    return newobj;
}
// 局部排序对象
function sortObject(obj){
  const newObj = {};
  const objKeys = Object.keys(obj)
  objKeys.sort().map((val) => {
      newObj[val] = obj[val];
  });
  return newObj;
}

const uniquedArr = uniqueByObjectKey(array);
console.log(uniquedArr);

结果:这里写图片描述此方法得到了“深去重*”的结果,因为我在函数中加了一些类型判断改变key,直接暴力object[原始key]会出现number与string被舍一,而且很多类型无法成为key,写函数过程中被JSON.stringify(/a/)坑了,还一直以为是{}的问题·~·,后来输出所以key才发现JSON.string(/a/) === ‘{}’,而String([]) === ”,所以得两个都转然后相加以避免意外。空间复杂度为O(N),时间复杂度为O(N),适用于想深度取重的场合(*:深去重我自个儿想的名字,因为对象是本身无序的,即{a:1,b:2}应该与{b:2,a:1}等价,所以深度去重把Object内部key:value都相同也进行去重)。
4. ES6 Set法:

const array = [1, NaN, '1', null, /a/, 1, undefined, null, NaN, '1', {}, /a/, [], undefined, {}, []];
function uniqueByES6Set(arr) {
  return Array.from(new Set(arr))  // return [...new Ser(arr)]
}
const uniquedArr = uniqueByES6Set(array);
console.log(uniquedArr);

结果:这里写图片描述
从结果看Array、Object、RegExp进行了保留,此方法原理是ES6的新数据结构Set,里面存储无序不重复数据,Set结构详情参阅:Set与Map-阮一峰,空间复杂度O(N),时间复杂度位置,·这方法速度很快,保留复杂对象时直接用这个最好咯。
5. ES6 Map法:

const array = [1, NaN, '1', null, /a/, 1, undefined, null, NaN, '1', {}, /a/, [], undefined, {}, []];
function uniqueByES6Map(arr) {
  const map = new Map();
  return arr.filter(e => {
    return map.has(e) ? false : map.set(e, 'map')
  })
}
const uniquedArr = uniqueByES6Map(array);
console.log(uniquedArr);

结果:这里写图片描述结果和用Set时一样的,主要用到了ES6的新数据结构Map,Map以key-value组映射存储,特点是key可以为任意类型,通过hash地址映射数据,时间复杂度O(1),空间复杂度比O(N),不过实际花费地址比Set的大些,也适用于保留复杂对象的情况。

本文记载了五种较为常见的数组除重方式,原则上直接用ES6的Set来的最快,如果有要除对象数组的可以使用第三种,当然第三种稍微一改结果就和后面的一样了

猜你喜欢

转载自blog.csdn.net/qq_39300332/article/details/79760304