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


    前言

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

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

     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"); // true
    console.log(1 === "1"); // false
    
    console.log(0 == "0"); // true
    console.log(0 === "0"); // false
    
    console.log(0 == +0); // true
    console.log(0 === +0); // true
    
    console.log(0 == -0); // true
    console.log(0 === -0); // true
    
    console.log(+0 == -0); // true
    console.log(+0 === -0); // true
    
    console.log(0 == false); // true
    console.log(0 === false); // false
    
    console.log(0 == undefined); // false
    console.log(0 === undefined); // false
    
    console.log(0 == null); // false
    console.log(0 === null); // false
    
    console.log(1 == true); // true
    console.log(1 === true); // false
    
    console.log(undefined == null); // true
    console.log(undefined === null); // false
    
    console.log(NaN == NaN); // false
    console.log(NaN === NaN); // false
    
    console.log(new String("1") == new String("1")); // false
    console.log(new String("1") === new String("1")); // false
    Object.prototype.toString.call(new String('1')) // '[object String]'
    
    
    console.log(/a/ == /a/); // false
    console.log(/a/ === /a/); // false
    Object.prototype.toString.call(/a/); //'[object RegExp]'
    
    
    console.log(Symbol(1) == Symbol(1)); // false
    console.log(Symbol(1) === Symbol(1)); // false
    
    console.log({} == {}); // false
    console.log({} === {}); // false
    
    console.log([] == []); // false
    console.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/, [], []]
    

    输出结果说明:

    1. 去重+0-00
    2. NaN不去重
    3. 对象new String("1")/a/{}不去重
    4. 数组[]不去重
    5. 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/, [], []]
    

    输出结果说明:

    1. 去重+0-00
    2. 去重NaN
    3. 对象new String("1")/a/{}不去重
    4. 数组[]不去重
    5. 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/, [], []]
    

    输出结果说明:

    1. 去重+0-00
    2. NaN不去重
    3. 对象new String("1")/a/{}不去重
    4. 数组[]不去重
    5. 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/, [], []]
    

    输出结果说明:

    1. 去重+0-00
    2. 两个NaN都会被删除
    3. 对象new String("1")/a/{}不去重
    4. 数组[]不去重
    5. 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]
    

    输出结果说明:

    1. +0-00"0"位置不同会导致去重不了
    2. NaN不去重
    3. 对象new String("1")/a/{}不去重
    4. 数组[]不去重
    5. 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/, [], []]
    

    输出结果说明:

    1. 去重+0-00
    2. 去重NaN
    3. 对象new String("1")/a/{}不去重
    4. 数组[]不去重
    5. 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/, [], []]
    

    输出结果说明:

    1. 去重+0-00
    2. 去重NaN
    3. 对象new String("1")/a/{}不去重
    4. 数组[]不去重
    5. 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), {}, []]
    

    输出结果说明:

    1. 去重+0-00
    2. 去重NaN
    3. 去重对象new String("1"){};两个/a/全部被删除了
    4. 去重数组[]
    5. 去重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】之数组去重(结果对比)

  • 相关阅读:
    【PyCharm Community Edition】:PCAN-USB上位机开发
    上海建筑模板厂家:承载城市梦想的力量
    .NET周刊【6月第1期 2024-06-02】
    jsp基础语法
    2022年电动车与车辆工程国际会议(CEVVE 2022)
    MLOps是什么,为什么重要,以及如何实现?
    H3C交换机如何重置console口密码
    更改libstdc++版本流程
    刷题5-合并两个有序数组
    vue3 接入网易易盾
  • 原文地址:https://www.cnblogs.com/yihan123/p/16500323.html