当前位置 : 主页 > 网络编程 > JavaScript >

JavaScript常用数组去重的方法及对比详解

来源:互联网 收集:自由互联 发布时间:2023-01-17
目录 前言 特殊类型 代码一(暴力解法) 代码二(ES6) 代码三(indexOf + forEach) 代码四(indexOf + filter) 代码五(sort排序,不支持Symbol) 代码六(includes) 代码七(includes+reduce) 代码八(
目录
  • 前言
  • 特殊类型
  • 代码一(暴力解法)
  • 代码二(ES6)
    • 代码三(indexOf + forEach)
    • 代码四(indexOf + filter)
  • 代码五(sort排序,不支持Symbol)
    • 代码六(includes)
      • 代码七(includes+reduce)
        • 代码八(对象key)
          • 总结
            • 演示地址

              前言

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

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

               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/, [], []]

              输出结果说明:

              • 去重+0-00
              • NaN不去重
              • 对象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-00
              • NaN不去重
              • 对象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常用数组去重的方法及对比详解的文章就介绍到这了,更多相关JavaScript数组去重内容请搜索自由互联以前的文章或继续浏览下面的相关文章希望大家以后多多支持自由互联!

              网友评论