当前位置:首页 » 《随便一记》 » 正文

【跟着大佬学JavaScript】之数组去重(结果对比)

11 人参与  2022年07月25日 10:33  分类 : 《随便一记》  评论

点击全文阅读


前言

数组去重在面试和工作中都是比较容易见到的问题。

这篇文章主要是来测试多个方法,对下面这个数组的去重结果进行分析讨论。如果有不对的地方,还请大家指出。

 const arr = [ 1, 1, "1", "1", 0, 0, "0", "0", true, false, "true", "false", "a", "A", undefined, undefined, "undefined", null, null, 'null', NaN, NaN, +0, -0, new String("1"), new String("1"), Symbol(1), Symbol(1), {}, {}, /a/, /a/, [], [] ];

特殊类型

console.log(1 == "1"); // trueconsole.log(1 === "1"); // falseconsole.log(0 == "0"); // trueconsole.log(0 === "0"); // falseconsole.log(0 == +0); // trueconsole.log(0 === +0); // trueconsole.log(0 == -0); // trueconsole.log(0 === -0); // trueconsole.log(+0 == -0); // trueconsole.log(+0 === -0); // trueconsole.log(0 == false); // trueconsole.log(0 === false); // falseconsole.log(0 == undefined); // falseconsole.log(0 === undefined); // falseconsole.log(0 == null); // falseconsole.log(0 === null); // falseconsole.log(1 == true); // trueconsole.log(1 === true); // falseconsole.log(undefined == null); // trueconsole.log(undefined === null); // falseconsole.log(NaN == NaN); // falseconsole.log(NaN === NaN); // falseconsole.log(new String("1") == new String("1")); // falseconsole.log(new String("1") === new String("1")); // falseObject.prototype.toString.call(new String('1')) // '[object String]'console.log(/a/ == /a/); // falseconsole.log(/a/ === /a/); // falseObject.prototype.toString.call(/a/); //'[object RegExp]'console.log(Symbol(1) == Symbol(1)); // falseconsole.log(Symbol(1) === Symbol(1)); // falseconsole.log({} == {}); // falseconsole.log({} === {}); // falseconsole.log([] == []); // falseconsole.log([] === []); // false

接下来,我们看看下面多个去重方法,对以上特殊类型的去重效果。

代码一(暴力解法)

// 暴力解法一function unique(array) {    if (!Array.isArray(array)) {      console.log("type error!");      return;    }    const res = [array[0]];    let arrLen = array.length;    let resLen = res.length;        for (let i = 0; i < arrLen; i++) {      let flag = true;      for (let j = 0; j < resLen; j++) {        if (array[i] === res[j]) {          flag = false;          break;        }      }      if (flag) {        res.push(array[i]);        resLen = res.length;      }    }    return res;}// [1, '1', 0, '0', true, false, 'true', 'false', 'a', 'A', undefined, 'undefined', null, 'null', NaN, NaN, String {'1'}, String {'1'}, Symbol(1), Symbol(1), {}, {}, /a/, /a/, [], []]

输出:

[1, '1', 0, '0', true, false, 'true', 'false', 'a', 'A', undefined, 'undefined', null, 'null', NaN, NaN, String {'1'}, String {'1'}, Symbol(1), Symbol(1), {}, {}, /a/, /a/, [], []]

输出结果说明:

去重+0-00NaN不去重对象new String("1")/a/{}不去重数组[]不去重Symbol(1)不去重

暴力解法,简单易理解,兼容性好。去重结果如上所示。

代码二(ES6)

// ES6 Array.from + Set 方法一function unique(array) {    if (!Array.isArray(array)) {      console.log('type error!')      return    }    return Array.from(new Set(array))}// ES6 点运算 + Set 方法二function unique1(array) {    if (!Array.isArray(array)) {      console.log('type error!')      return    }    return [...new Set(arr)]}// ES6 箭头函数 + 点运算 + Set 方法三const unique2 = (array) => {    if (!Array.isArray(array)) {      console.log('type error!')      return    }    return [...new Set(arr)]}// ES6 Map + ES5 filter  方法四function unique3(array) {    if (!Array.isArray(array)) {      console.log('type error!')      return    }    const seen = new Map()    return array.filter((a) => !seen.has(a) && seen.set(a, 1))}

输出:

[1, '1', 0, '0', true, false, 'true', 'false', 'a', 'A', undefined, 'undefined', null, 'null', NaN, String {'1'}, String {'1'}, Symbol(1), Symbol(1), {}, {}, /a/, /a/, [], []]

输出结果说明:

去重+0-00去重NaN对象new String("1")/a/{}不去重数组[]不去重Symbol(1)不去重

代码三(indexOf + forEach)

利用indexOf检测元素在新数组是否存在

// indexOf + forEach 利用indexOf检测元素在新数组是否存在function unique(array) {    if (!Array.isArray(array)) {        console.log('type error!')        return    }    const newArr = [];    array.forEach((el) => {      if (newArr.indexOf(el) === -1) {        newArr.push(el);      }    });    return newArr;}

输出:

[1, '1', 0, '0', true, false, 'true', 'false', 'a', 'A', undefined, 'undefined', null, 'null', NaN, NaN, String {'1'}, String {'1'}, Symbol(1), Symbol(1), {}, {}, /a/, /a/, [], []]

输出结果说明:

去重+0-00NaN不去重对象new String("1")/a/{}不去重数组[]不去重Symbol(1)不去重

代码四(indexOf + filter)

利用indexOf检测元素在数组中第一次出现的位置是否和元素现在的位置相等

// indexOf + forEach 利用indexOf检测元素在新数组是否存在function unique(array) {    if (!Array.isArray(array)) {        console.log('type error!')        return    }    return array.filter((item, index) => {        return array.indexOf(item) === index;    });}console.log([NaN].indexOf(NaN)); // -1

输出:

[1, '1', 0, '0', true, false, 'true', 'false', 'a', 'A', undefined, 'undefined', null, 'null', String {'1'}, String {'1'}, Symbol(1), Symbol(1), {}, {}, /a/, /a/, [], []]

输出结果说明:

去重+0-00两个NaN都会被删除对象new String("1")/a/{}不去重数组[]不去重Symbol(1)不去重

重点:

console.log([NaN].indexOf(NaN)); // -1

代码五(sort排序,不支持Symbol)

sort()方法主要是用于对数组进行排序,默认情况下该方法是将数组元素转换成字符串,然后按照ASC码进行排序

// sort()方法不支持Symbol,Symbol不支持转换成字符串function unique(array) {    if (!Array.isArray(array)) {      console.log("type error!");      return;    }    const sortArr = array.sort();    const newArr = [];    sortArr.forEach((el, i) => {      if (sortArr[i] !== sortArr[i - 1]) {        newArr.push(el);      }    });    return newArr;}

输出:

[[], [], /a/, /a/, 0, "0", 0, 1, "1", String {'1'}, String {'1'}, "A", NaN, NaN, {}, {}, "a", false, "false", null, "null", true, "true", "undefined", undefined]

输出结果说明:

+0-00"0"位置不同会导致去重不了NaN不去重对象new String("1")/a/{}不去重数组[]不去重sort()方法不支持处理含有Symbol的数组

代码六(includes)

利用includes()方法检查新数组是否包含原数组的每一项

// 利用includes()方法检查新数组是否包含原数组的每一项function unique(array) {    if (!Array.isArray(array)) {      console.log("type error!");      return;    }        const newArr = [];    array.forEach((el) => {      newArr.includes(el) ? newArr : newArr.push(el);    });    return newArr;}

输出:

[1, '1', 0, '0', true, false, 'true', 'false', 'a', 'A', undefined, 'undefined', null, 'null', NaN, String {'1'}, String {'1'}, Symbol(1), Symbol(1), {}, {}, /a/, /a/, [], []]

输出结果说明:

去重+0-00去重NaN对象new String("1")/a/{}不去重数组[]不去重Symbol不去重

代码七(includes+reduce)

利用includes()方法检查新数组是否包含原数组的每一项

// 利用includes()方法检查新数组是否包含原数组的每一项function unique(array) {    if (!Array.isArray(array)) {      console.log("type error!");      return;    }        return array.reduce((pre, cur) => {      !pre.includes(cur) && pre.push(cur);      return pre;    }, []);}

输出:

[1, '1', 0, '0', true, false, 'true', 'false', 'a', 'A', undefined, 'undefined', null, 'null', NaN, String {'1'}, String {'1'}, Symbol(1), Symbol(1), {}, {}, /a/, /a/, [], []]

输出结果说明:

去重+0-00去重NaN对象new String("1")/a/{}不去重数组[]不去重Symbol不去重

代码八(对象key)

利用了对象的key不可以重复的特性来进行去重

// 利用了对象的key不可以重复的特性来进行去重function unique(array) {    if (!Array.isArray(array)) {      console.log("type error!");      return;    }        const obj = {};    const newArr = [];    array.forEach((val) => {      if (!obj[typeof val + JSON.stringify(val)]) {        // 将对象序列化之后作为key来使用        obj[typeof val + JSON.stringify(val)] = 1;        newArr.push(val);      }    });    return newArr;}

输出:

[1, '1', 0, '0', true, false, 'true', 'false', 'a', 'A', undefined, 'undefined', null, 'null', NaN, String {'1'}, Symbol(1), {}, []]

输出结果说明:

去重+0-00去重NaN去重对象new String("1"){};两个/a/全部被删除了去重数组[]去重Symbol

将不该去重的Symbol去重了;将两个/a/全部删除了

总结

方法结果说明
for循环暴力解法[1, '1', 0, '0', true, false, 'true', 'false', 'a', 'A', undefined, 'undefined', null, 'null', NaN, NaN, String {'1'}, String {'1'}, Symbol(1), Symbol(1), {}, {}, /a/, /a/, [], []]1.去重+0、-0、0; 2.NaN不去重;3.对象new String(“1”)、/a/、{}不去重;4.数组[]不去重;5.Symbol(1)不去重;
ES6解法[1, '1', 0, '0', true, false, 'true', 'false', 'a', 'A', undefined, 'undefined', null, 'null', NaN, String {'1'}, String {'1'}, Symbol(1), Symbol(1), {}, {}, /a/, /a/, [], []1.去重+0、-0、0; 2.去重NaN;3.对象new String(“1”)、/a/、{}不去重;4.数组[]不去重;5.Symbol(1)不去重;
indexOf + forEach[1, '1', 0, '0', true, false, 'true', 'false', 'a', 'A', undefined, 'undefined', null, 'null', NaN, NaN, String {'1'}, String {'1'}, Symbol(1), Symbol(1), {}, {}, /a/, /a/, [], []]1.去重+0、-0、0; 2.NaN不去重;3.对象new String(“1”)、/a/、{}不去重;4.数组[]不去重;5.Symbol(1)不去重;
indexOf + filter[1, '1', 0, '0', true, false, 'true', 'false', 'a', 'A', undefined, 'undefined', null, 'null', String {'1'}, String {'1'}, Symbol(1), Symbol(1), {}, {}, /a/, /a/, [], []]1.去重+0、-0、0; 2.两个NaN都会被删除;3.对象new String(“1”)、/a/、{}不去重;4.数组[]不去重;5.Symbol(1)不去重;
sort排序,不支持Symbol[[], [], /a/, /a/, 0, "0", 0, 1, "1", String {'1'}, String {'1'}, "A", NaN, NaN, {}, {}, "a", false, "false", null, "null", true, "true", "undefined", undefined]1.+0、-0、0、"0"位置不同会导致去重不了 2.NaN不去重;3.对象new String(“1”)、/a/、{}不去重;4.数组[]不去重;5.sort()方法不支持处理含有Symbol的数组;
includes[1, '1', 0, '0', true, false, 'true', 'false', 'a', 'A', undefined, 'undefined', null, 'null', NaN, String {'1'}, String {'1'}, Symbol(1), Symbol(1), {}, {}, /a/, /a/, [], []]1.去重+0、-0、0; 2.去重NaN;3.对象new String(“1”)、/a/、{}不去重;4.数组[]不去重;5.Symbol(1)不去重;
includes+reduce[1, '1', 0, '0', true, false, 'true', 'false', 'a', 'A', undefined, 'undefined', null, 'null', NaN, String {'1'}, String {'1'}, Symbol(1), Symbol(1), {}, {}, /a/, /a/, [], []]1.去重+0、-0、0; 2.去重NaN;3.对象new String(“1”)、/a/、{}不去重;4.数组[]不去重;5.Symbol(1)不去重;
对象key[1, '1', 0, '0', true, false, 'true', 'false', 'a', 'A', undefined, 'undefined', null, 'null', NaN, String {'1'}, Symbol(1), {}, []]1.去重+0、-0、0; 2.去重NaN;3.去重对象new String(“1”)、{};两个/a/全部被删除了;4.去重数组[];5.去重Symbol

上面只是简单结果的去重总结,具体的去重选择还需要根据我们业务场景来选择去重方法。

演示地址

可以去Github仓库查看演示代码

跟着大佬学系列

主要是日常对每个进阶知识点的摸透,跟着大佬一起去深入了解JavaScript的语言艺术。

后续会一直更新,希望各位看官不要吝啬手中的赞。

❤️ 感谢各位的支持!!!

❤️ 如果有错误或者不严谨的地方,请务必给予指正,十分感谢!!!

❤️ 喜欢或者有所启发,欢迎 star!!!

参考

解锁多种JavaScript数组去重姿势数组去重的六种方法7种方法实现数组去重JavaScript专题之数组去重

原文地址

【跟着大佬学JavaScript】之数组去重(结果对比)


点击全文阅读


本文链接:http://zhangshiyu.com/post/43768.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1