再见,重复的你

1,201 阅读6分钟

前言

文章涉及的内容可能不全面,但量很多,需要慢慢看。我花了很长的时间整理,用心分享心得,希望对大家有所帮助。但是难免会有打字的错误或理解的错误点,希望发现的可以邮箱告诉我ghui_master@163.com,我会及时的进行修改,只希望对你有所帮助,谢谢。

hahaha

昨天跟在前端好友聊天时,他提到了一个问题:“数组去重你会怎么写?"。想了想,其实有好几种方法,决定在这篇笔记中做一些记录。

数组去重,一般都是在面试的时候才会碰到,一般是要求手写数组去重方法的代码。如果是被提问到,数组去重的方法有哪些?你能答出其中的10种,面试官很有可能对你刮目相看。

在真实的项目中碰到的数组去重,一般都是后台去处理,很少让前端处理数组去重。虽然日常项目用到的概率比较低,但还是需要了解一下,以防面试的时候可能回被问到。

### 思路一:

  1. 双层循环,外层循环元素,内层循环时比较值
  2. 如果有相同的值则跳过,不相同则push进数组
Array.prototype.distinct = function(){
    var arr = this,
        result = [],
        i,
        j,
        len = arr.length;

    for(i = 0; i < len; i++){
        for(j = i + 1; j < len; j++){
            if(arr[i] === arr[j]){
                j = ++i;
            }
        }
        result.push(arr[i]);
    }
    return result;
}
var arra = [1,2,3,4,4,1,1,2,1,1,1];
arra.distinct();             //返回[3,4,2,1]

思路二:利用for嵌套for,基于splice直接在原数组进行操作(ES5常用)

  1. 双层循环,外层循环元素,内层循环时比较值
  2. 值相同时,则删去这个值

注意点:删除元素之后,需要将数组的长度也减1.

Array.prototype.distinct = function (){
    var arr = this,
        i,
        j,
        len = arr.length;

    for(i = 0; i < len; i++){
        for(j = i + 1; j < len; j++){
            if(arr[i] === arr[j]){  //第一个等同于第二个,splice方法删除第二个
                arr.splice(j,1);
                len--;
                j--;
            }
        }
    }
    return arr;
};

var a = [1,2,3,4,5,6,5,3,2,4,56,4,1,2,1,1,1,1,1,1,];
var b = a.distinct();
console.log(b.toString()); //1,2,3,4,5,6,56

优点:简单易懂 缺点:占用内存高,速度慢

思路三:利用对象的属性不能相同的特点进行去重

Array.prototype.distinct = function (){
    var arr = this,
        i,
        obj = {},
        result = [],
        len = arr.length;

    for(i = 0; i< arr.length; i++){
        if(!obj[arr[i]]){    //如果能查找到,证明数组元素重复了
            obj[arr[i]] = 1;
            result.push(arr[i]);
        }
    }
    return result;
};

var a = [1,2,3,4,5,6,5,3,2,4,56,4,1,2,1,1,1,1,1,1,];
var b = a.distinct();
console.log(b.toString()); //1,2,3,4,5,6,56

思路四、数组递归去重

  1. 运用递归的思想
  2. 先排序,然后从最后开始比较,遇到相同,则删除
Array.prototype.distinct = function (){
    var arr = this,
        len = arr.length;

    arr.sort(function(a,b){        //对数组进行排序才能方便比较
        return a - b;
    })

    function loop(index){
        if(index >= 1){
            if(arr[index] === arr[index-1]){
                arr.splice(index,1);
            }
            loop(index - 1);    //递归loop函数进行去重
        }
    }
    loop(len-1);

    return arr;
};

var a = [1,2,3,4,5,6,5,3,2,4,56,4,1,2,1,1,1,1,1,1,56,45,56];
var b = a.distinct();
console.log(b.toString());        //1,2,3,4,5,6,45,56

思路五、利用indexOf以及forEach

新建一个空的结果数组,for 循环原数组,判断结果数组是否存在当前元素,如果有相同的值则跳过,不相同则push进数组。

Array.prototype.distinct = function (){
    var arr = this,
        result = [],
        len = arr.length;

    arr.forEach(function(v, i ,arr){        //这里利用map,filter方法也可以实现
        var bool =  arr.indexOf(v,i+1);        //从传入参数的下一个索引值开始寻找是否存在重复
        if(bool === -1){
            result.push(v);
        }
    })

    return result;
};

var a = [1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,3,2,3,3,2,2,1,23,1,23,2,3,2,3,2,3];
var b = a.distinct();
console.log(b.toString());    //1,23,2,3

思路六、利用indexOf以及sort(不推荐)

注意:这个方法依赖于浏览器内置Array类的sort方法,由于浏览器不同,效果就不同。 利用sort()排序方法,然后根据排序后的结果进行遍历及相邻元素比对。

Array.prototype.distinct = function (){
    var arr = this,
        len = arr.length,
        list = arr.concat().sort();    //注意这个地方的concat:复制一个新的数组
    list.sort(function(a,b){
        if(a === b){
            var index = arr.indexOf(a);
            arr.splice(index,1);    //在复制的数组进行排序(相邻的两个元素进行比较)时,操作原有数组arr
        }
    });
    return arr;
};

var a = [1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,3,2,3,3,2,2,1,23,1,23,2,3,2,3,2,3,25];
var b = a.distinct();
console.log(b.toString());

思路七、利用ES6的set (ES6中最常用) [...new Set(arr)]

Set数据结构,它类似于数组,其成员的值都是唯一的。

  1. 利用Array.from将Set结构转换成数组
function dedupe(array){
    return Array.from(new Set(array));
}

dedupe([1,1,2,3]) //[1,2,3]
  1. 拓展运算符(...)内部使用for...of循环
let arr = [3,5,2,2,5,5];
let unique = [...new Set(arr)];    //[3,5,2]


[...new Set(arr)] 
//代码就是这么少----(其实,严格来说并不算是一种,相对于第一种方法来说只是简化了代码)

思路八:利用reduce+includes

function unique(arr){
    return arr.reduce((prev,cur) => prev.includes(cur) ? prev : [...prev,cur],[]);
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr));
// [1, "true", true, 15, false, undefined, null, NaN, "NaN", 0, "a", {…}, {…}]

思路九:利用hasOwnProperty

function unique(arr) {
    var obj = {};
    return arr.filter(function(item, index, arr){
        return obj.hasOwnProperty(typeof item + item) ? false : (obj[typeof item + item] = true)
    })
}
    var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
        console.log(unique(arr))
//[1, "true", true, 15, false, undefined, null, NaN, "NaN", 0, "a", {…}]   //所有的都去重了

利用hasOwnProperty 判断是否存在对象属性

思路十:利用filter

function unique(arr) {
  return arr.filter(function(item, index, arr) {
    //当前元素,在原始数组中的第一个索引==当前索引值,否则返回当前元素
    return arr.indexOf(item, 0) === index;
  });
}
    var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
        console.log(unique(arr))
//[1, "true", true, 15, false, undefined, null, "NaN", 0, "a", {…}, {…}]

思路十一:利用Map数据结构去重

function arrayNonRepeatfy(arr) {
  let map = new Map();
  let array = new Array();  // 数组用于返回结果
  for (let i = 0; i < arr.length; i++) {
    if(map .has(arr[i])) {  // 如果有该key值
      map .set(arr[i], true); 
    } else { 
      map .set(arr[i], false);   // 如果没有该key值
      array .push(arr[i]);
    }
  } 
  return array ;
}
 var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
    console.log(unique(arr))
//[1, "a", "true", true, 15, false, 1, {…}, null, NaN, NaN, "NaN", 0, "a", {…}, undefined]

创建一个空Map数据结构,遍历需要去重的数组,把数组的每一个元素作为key存到Map中。由于Map中不会出现相同的key值,所以最终得到的就是去重后的结果。

愿每个人都带着最初的心收获最完美的结局