数组去重方法总结

在这里插入图片描述

1 双层 for 循环

var array = [1, 1, "1", "1", 1];

// 写法一
function unique(arr) {
  let res = [...array];

  for (let i = 0; i < res.length; i++) {
    for (let j = i + 1; j < res.length; j++) {
      if ((res[i] === res[j])) {
        res.splice(j, 1);
        j--;
      }
    }
  }

  return res;
}

// 写法二
function unique(arr) {
  var res = [];

  for (var i = 0; i < arr.length; i++) {
    for (var j = 0; j < res.length; j++) {
      if (arr[i] === res[j]) break;
    }

    if (j === res.length) res.push(arr[i]);
  }

  return res;
}

2 for 循环 + indexOf()

使用 indexOf() 简化内层循环。

var array = [1, 1, "1", "1", 1];

function unique(arr) {
  var res = [];

  for (var i = 0; i < arr.length; i++) {
    if (res.indexOf(arr[i]) === -1) {
      res.push(arr[i]);
    }
  }

  return res;
}

3 filter() + indexOf()

var array = [1, "1", "1", 1];

function unique(arr) {
  return arr.filter((item, index) => {
    return arr.indexOf(item) === index;
  });
}

4 for 循环 + includes()

var array = [1, "1", "1", 1];

function unique(arr) {
  var res = [];

  for (var i = 0, len = arr.length; i < len; i++) {
    if (!res.includes(arr[i])) {
      res.push(arr[i]);
    }
  }

  return res;
}

5 reduce() + includes()

var array = [1, "1", "1", 1];

function unique(arr) {
  return arr.reduce((prev, cur) => {
    return prev.includes(cur) ? prev : [...prev, cur];
  }, []);
}

6 sort()

var array = [1, "1", "1", 1];

function unique(arr) {
  // sort():默认排序顺序是在将元素转换为字符串
  var sortedArr = arr.sort();
  var res = [];

  for (var i = 0, len = sortedArr.length; i < len; i++) {
    if (!i || sortedArr[i] !== sortedArr[i - 1]) {
      res.push(sortedArr[i]);
    }
  }

  return res;
}

ES6 语法去重

7 Set()

利用了 Set 中的元素是唯一性的特点

var array = [1, "1", "1", 1];

function unique(arr) {
  return [...new Set(arr)]
}

8 Map()

var array = [1, "1", "1", 1];

function unique(arr) {
  const myMap = new Map();
  return arr.filter((v) => !myMap.has(v) && myMap.set(v, true));
}

特殊类型比较

原始值的比较是值的比较:

它们的值相等时它们就相等(==);

console.log(1 == '1');  // true 两者转换成数字再比较值

它们的值和类型都相等时,它们就全等(===);

console.log(1 === '1');  // false
console.log(1 === 1);    // true

对象的比较并非值的比较,而是引用的比较:

即使两个对象包含同样的属性及相同的值,它们也是不相等的。

var obj1 = { x: 1 };
var obj2 = { x: 1 };

console.log(obj1 == obj2);  // false

当且仅当它们引用同一个对象时,才会全等(===

var a = { x: 1 };
var b = a;

console.log(a === b);   // true

其它特殊类型比较

var str1 = '1';
var str2 = new String('1');

console.log(str1 == str2);  // true 
console.log(str1 === str2); // false 一个数据类型为 'string',另一个数据类型为 'object'

console.log(null == null);  // true:null 类型只有一个值,那就是 null 本身,所以相等(==)
console.log(null === null); // true:数据类型都是 'object'

console.log(undefined == undefined); // true:undefined 类型只有一个值,那就是 undefined,所以相等(==)
console.log(undefined === undefined); // true:数据类型都是 'undefined'

console.log(NaN == NaN);  // false:NaN 等于任何值,包括自身
console.log(NaN === NaN); // false:数据类型都是 'object',但值不相等

console.log({} == {});  // false:对象是引用的比较
console.log({} === {}); // false

那么,对于这样的一个数组

var array = [1, 1, '1', '1', null, null, undefined, undefined, new String('1'), new String('1'), NaN, NaN];

上面的去重方法的结果怎么样呢?

重点关注下对象和 NaN 的去重情况

方法结果说明
双层 for 循环[1, ‘1’, null, undefined, String, String, NaN, NaN]对象和 NaN 都不去重
for 循环 + indexOf()[1, ‘1’, null, undefined, String, String, NaN, NaN]对象和 NaN 都不去重
filter() + indexOf()[1, ‘1’, null, undefined, String, String]对象不去重,NaN 会被忽略掉
for 循环 + includes()[1, ‘1’, null, undefined, String, String, NaN]对象不去重,NaN 去重
reduce() + includes()[1, ‘1’, null, undefined, String, String, NaN]对象不去重,NaN 去重
sort()[1, ‘1’, String, String, NaN, NaN, null, undefined]对象和 NaN 都不去重
Set()[1, ‘1’, null, undefined, String, String, NaN]对象不去重,NaN 去重
Map()[1, ‘1’, null, undefined, String, String, NaN]对象不去重,NaN 去重

9 Object 键值对

上面的去重方法都不能去重对象,那么如何去重属性都相同的对象呢?

我们可以利用一个空的 Object 对象,把数组的值存成 Object 的key值,比如Object[value1] = true,在判断另一个值的时候,如果Object[value2]存在的话,就说明该值是重复的。

var array = [1, 2, 1, 1, "1"];

function unique(array) {
  var obj = {};

  return array.filter(function (item, index) {
    return obj.hasOwnProperty(item) ? false : (obj[item] = true);
  });
}

// [1, 2]

可以发现结果是有问题的,没能正确区分1'1',这是因为对象的键值都是字符串。

所以可以使用typeof item + item拼成字符串作为key值来避免这个问题。

var array = [1, 2, 1, 1, "1"];

function unique(array) {
  var obj = {};

  return array.filter(function (item, index) {
    return obj.hasOwnProperty(typeof item + item) ? false : (obj[typeof item + item] = true);
  });
}

// [1, 2, '1']

然而,即便如此,依然无法正确区分出两个对象,比如{ value: 1 },{ value: 2 },因为两者typeof item + item的结果都是object[object Object],不过可以使用JSON.stringify将对象序列化。

var array = [1, 1, "1", "1", { value: 1 }, { value: 2 }, { value: 1 }, null, null, undefined, undefined, NaN, NaN];

function unique(array) {
  var obj = {};

  return array.filter(function (item, index) {
    return obj.hasOwnProperty(typeof item + JSON.stringify(item))
      ? false
      : (obj[typeof item + JSON.stringify(item)] = true);
  });
}

// [1, '1', { value: 1 }, { value: 2 }, null, undefined, NaN]

参考文章

JavaScript专题之数组去重

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值