zoukankan      html  css  js  c++  java
  • 关于数组去重

    【本文源址:http://blog.csdn.net/q1056843325/article/details/73277063 转载请添加该地址】

    JavaScript数组去重问题虽然在实际开发中很少应用 
    但却是面试(或笔试)中可能被问到的题 
    如果只能说出一两种方法的话,就显得我们很low 
    所以这里我总结了数组去重的六种方法供大家参考

    直接遍历

    首先先来一种简单粗暴的方法 
    也是很容易就可以想到的办法 
    声明一个新数组 
    直接遍历这个待去重数组 
    然后把新数组中没有的元素推进去

    function unique(arr){
      var newArr = [];
      for(var i = 0, item; item = arr[i++];){
        if(newArr.indexOf(item) === -1){
          newArr.push(item);
        }
      }
      return newArr;
    };

    测试数组

    var arr = [1,3,2,1,4,5,2,4,1,5];
    console.log(unique(arr)); //[1,3,2,4,5]

    这个结果是正确的 
    但是如果元素中有undefined或者null就会出现问题

    var arr = [1,3,2,1,null,4,5,2,4,1,5,null];
    console.log(unique(arr)); //[1,3,2]

    这是因为for(var i = 0, item; item = arr[i++];) 
    null导致提前跳出了循坏 
    没办法虽然我很喜欢这种循环方式 
    但是为了保持严谨还是要使用正常的for循环

    function unique(arr){
      var newArr = [];
      var item;
      for(var i = 0, len = arr.length; i < len; i++){
        item = arr[i];
        if(newArr.indexOf(item) === -1){
          newArr.push(item);
        }
      }
      return newArr;
    };
    var arr = [1,3,2,1,null,4,5,2,4,1,5,null];
    console.log(unique(arr)); //[1,3,2,null,4,5]

    当然也可以使用ES5的forEach方法 
    虽然它没有for循环的效率高

    function unique(arr){
      var newArr = [];
      arr.forEach(function(item){
        if(newArr.indexOf(item) === -1){
          newArr.push(item);
        }
      });
      return newArr;
    }

    下面的其他方法也可以把for循环替换成forEach


    除此之外,我们还可以使用ES5的reduce方法 
    让代码看起来更加高大上

    function unique(arr){
      return arr.reduce(function(prev, next){
        if(prev.indexOf(next) === -1){
          prev.push(next);
        }
        return prev;
      }, []);
    }

    indexOf也可以替换成循环判断 
    不过既然有好使的API就直接拿来用了 
    顺便一提,方法不能够处理数组NaN的去重

    var arr = [4, 2, 1, 3, 2, 3, NaN, NaN];
    console.log(unique(arr)); //[4,2,1,3,NaN,NaN]

    包括下面的方法都不可以 
    不过可以把indexOf()换成ES6的Array.contains() 
    真正意义上的绝对相等 
    这里我就不讨论太复杂的情况了

    索引判断

    这种方法是利用了数组indexOf的特点 
    它会找到数组中第一个该元素值的索引 
    所以我们可以判断数组元素的indexOf索引判断和元素本身的索引是否相同 
    如果相同,代表这是数组第一次出现的该元素值

    function unique(arr){
      var newArr = [];
      var item;
      for(var i = 0, len = arr.length; i < len; i++){
        item = arr[i];
        if(arr.indexOf(item) === i){
          newArr.push(item);
        }
      }
      return newArr;
    }

    我们还可以做一些小小的优化 
    因为实际上第一次是不需要判断的 
    数组元素的第一个值一定是首次出现的 
    所以从数组的第二个元素开始循环就可以了

    function unique(arr){
      var newArr = [arr[0]];
      var item;
      for(var i = 1, len = arr.length; i < len; i++){
        item = arr[i];
        if(arr.indexOf(item) === i){
          newArr.push(item);
        }
      }
      return newArr;
    }

    排序去邻

    这种方法的原理就是首先调用数组的sort方法 
    我们的目的不是给数组元素排序 
    所以也不需要为sort添加处理函数 
    目的是为了把相同的元素值聚在一起 
    这样只需要判断数组元素值和上一个索引值不同就可以了

    function unique(arr){
      var newArr = [arr[0]];
      var item;
      arr.sort();
      for(var i = 1, len = arr.length; i < len; i++){
        item = arr[i];
        if(item !== arr[i - 1]){
          newArr.push(item);
        }
      }
      return newArr;
    }

    优化遍历

    这种方法看起来特别梦幻 
    原理是不断的将数组最右边不重复的值推入新数组

    function unique(arr){
      var newArr = [];
      for(var i = 0, len = arr.length; i < len; i++){
        for(var j = i + 1; j < len; j++){
          if(arr[i] === arr[j]){
            j = ++i;
          }
        }
        newArr.push(arr[i]);
      }
      return newArr;
    };

    说的再详细一下 
    就是对数组的每一个元素都进行判断(指针i) 
    还有另一个指针从判断元素的下一位进行判断 
    移动这个指针(指针j下移) 
    如果发现判断元素与指针指向的值相等 
    证明该判断元素不是数组中唯一的 
    那么就继续往下判断(指针i下移,指针j回到i的下一位) 
    直到j移到数组终点 
    证明判断元素(指针i指向的元素)是数组中唯一的 
    推入新数组

    临时对象

    这种方法是很好的一种方法 
    借用了一个临时对象的数据结构 
    这个对象用来存储数组的元素

    function unique(arr){
      var newArr = [];
      var temp = {};
      var item;
      for(var i = 0, len = arr.length; i < len; i++){
        item = arr[i];
        if(!temp[item]){
          temp[item] = true;
          newArr.push(item);
        }
      }
      return newArr;
    }

    这是典型的空间换取时间思想的算法 
    如果数组很大可能会很占内存 
    但是效率很高这是毋庸置疑的 
    其实现在这个函数还是有缺点

    var arr = [1,3,2,1,4,5,2,4,1,5,'1','2'];
    console.log(unique(arr)); //[1,3,2,4,5]

    从这个测试中可以看到数组和字符没能有效区分 
    这是因为它们传入对象中会调用toString() 
    对象的键都是字符串 
    既然这样我们可以对函数做一些修改 
    让对象的键对应一个数组 
    数组存储着已有的类型

    function unique(arr){
      var newArr = [];
      var temp = {};
      var item;
      var type;
      for(var i = 0, len = arr.length; i < len; i++){
        item = arr[i];
        type = typeof item;
        if(!temp[item]){
          temp[item] = [type];
          newArr.push(item);
        }else if(temp[item].indexOf(type) === -1){
          temp[item].push(type);
          newArr.push(item);
        }
      }
      return newArr;
    }

    这样内存占用更大了 
    但是却更加严谨了

    var arr = [1,3,2,1,4,5,2,4,1,5,'1','2'];
    console.log(unique(arr)); //[1,3,2,4,5,"1","2"]

    集合转换

    集合这个数据结构最大的特点就是 
    集合内部的元素都是唯一的 
    ES6标准给我们提供了Set集合 
    利用这个新的数据结构我们可以很容易的实现数组去重 
    容易到什么程度呢? 
    一行.. 
    就够了

    function unique(arr){
      return Array.from(new Set(arr));
    }

    这才是真正的简单粗暴 
    将数组转为集合,抛弃多余数值 
    最后利用ES6的新数组方法Array.from将集合转为数组返回

    
    

    function unique(arr){returnArray.from(new Set(arr)); }

  • 相关阅读:
    BAT 批处理脚本教程
    javascript定时器
    使用命令行打开文件夹并显示
    用cmd加密文件夹
    烟波钓叟歌概述讲解
    奇门遁甲的起源
    八卦基本知识
    word2vec和word embedding有什么区别?
    Privoxy shadowscocks代理
    Elasticsearch源码分析—线程池(十一) ——就是从队列里处理请求
  • 原文地址:https://www.cnblogs.com/llfy/p/9476115.html
Copyright © 2011-2022 走看看