JavaScript数组去重

数组去重是一个经典的面试问题,这里记录一下自己的心得和常用的处理方法。

数字类型的数组去重&字符类型数组去重

对于数字类型数组 var arr = [1,2,3,4,3,2,1];去重或者对于字符类型数组 var arr = ['1','1','a','b','a'];去重

使用Set去重

function use_set(arr){
    return Array.from(new Set(arr));
}
复制代码

先排序再比较去重

1.先将原数组排序,数组会变成这样 [1,1,2,2,3,3,4] 2.逐个的取出数组中的元素,加入另一个临时数组init中,每次加入的时候判断,如果init为空,或者init的最后一个元素与当前要插入的不相等则插入 3.重复2的步骤直到遍历完数组,完成后init中保存的就是去重之后的数组元素

function reduce_sort(arr){
    arr.sort(); //先排序
    // 使用reduce挨个比较去重,去重后的结果保存在init数组中
    return arr.reduce(function(init,current){
        if(init.length === 0 || init[init.length-1]!=current){
            init.push(current)
        }
        return init
    },[]);
}
复制代码

使用indexOf过滤

indexOf可以从前往后查找元素在数组中出现的索引位置,如果没有找到就返回-1。由于每次的都是从前往后找,当有两个相同的值的时候,indexOf返回的是前一个值的,而当前索引必然大于indexOf直接返回,可以根据两者是否相等来过滤数组元素。

function use_filter(arr){
    return arr.filter(function(item,index,self){
        //从前往后查找对应元素的索引是否与当前索引相等,要是不相等说明之前出现过重复的元素
        return self.indexOf(item) === index;
    });
}
复制代码

使用Object的键值对去重

使用一个临时的对象obj来记录数组中的元素是否出现,其中将数组中的元素作为键,出现了就记为ture。之后通过hasOwnProperty来判断是否包含这个属性,包含就说明已经存在,不包含就添加为obj的新属性。

function use_object(arr){
    var obj = {};
    return arr.filter(function(item){
        return obj.hasOwnProperty(item) ? false : (obj[item] = true)
    })
}
复制代码

混合数据类型的数组去重

JavaScript中的数组存储的数据类型是可以不同的,也就是说JavaScript中的7种数据类型都可能出现在数组中,此时的去重又变得不一样了

数组中可能出现的数据类型

  • null
  • undefined
  • String
  • Number
  • Object
  • Boolean
  • Symbol 另外数组中的元素还可能是数组、函数、日期、正则等其他的特殊对象类型。 对于indexOf在底层使用的方法是用===进行判断,下面是用===判断是否相等的例子,可以发现有很多类型是不能直接用 ===判断的
console.log(null === null); // true
console.log(undefined === undefined); // true
console.log('a' === 'a'); //true
console.log(String('a') === String('a')); // true
console.log(1 === 1); // true
console.log({} === {}); // false
console.log(true === true); // true
console.log(Symbol() === Symbol()); // false
console.log([] === []); // false
console.log(/a/ === /a/); //false
console.log(function(){console.log("1")} === function(){console.log("1")}); //false
console.log(NaN === NaN); // false
复制代码

使用Object键值对去重的时候,需要转成字符串,下面看一下几个转字符串的情况

console.log(1..toString());//1
console.log('1'.toString());//1
console.log([1,function(){console.log("!")},NaN,undefined,null].toString());
//1,function(){console.log("!")},NaN,,
console.log({"a":1}.toString());//[object Object]
复制代码

我只是尝试了几种类型,发现undefined和null在数组中的时候并不能够转成字符串,获取还存在其他的情况我没有发现。下面再试试JSON.stringify()序列化试试,发现也是有很多元素是不能够直接序列化为字符串的,其他JSON.stringify()的序列化问题参考blog.fundebug.com/2017/08/17/…

console.log(JSON.stringify([1,2,function(){console.log("1")},NaN,undefined,null]))
// [1,2,null,null,null,null
复制代码

先尝试用set去重

无法对对象类型的数据进行去重

var arr = [1,1,'1','1',0,0,'0','0',undefined,undefined,null,null,NaN,NaN,{},{},[],[],/a/,/a/,function(){console.log(1)},function(){console.log(1)}]
function use_set(arr){
    return Array.from(new Set(arr));
}
console.log(use_set(arr));
/* [ 1,
  '1',
  0,
  '0',
  undefined,
  null,
  NaN,
  {},
  {},
  [],
  [],
  /a/,
  /a/,
  [Function],
  [Function] ]
  */
复制代码

将indexOf换成includes

indexOf的比较是 ===inclues的比较比indexOf改进的地方是能够判断NaN

If Type(x) is different from Type(y), return false.
If Type(x) is Number, then
a. If x is NaN and y is NaN, return true.
b. If x is +0 and y is -0, return true.
c. If x is -0 and y is +0, return true.
d. If x is the same Number value as y, return true.
e. Return false.
Return SameValueNonNumber(x, y)
复制代码

最后的解决方案

对于对象类型的使用JSON.stringify序列化为字符串,但是我没有处理不能序列化的情况,然后是用typeof+item来代替item避免出现1'1'同时作为key的情况

  function func(arr){
      var obj = {};
      var res = arr.filter(function(item){
          let key;
          if(typeof(item)==="object"){
            //  对于object使用JSON.stringify
              key = JSON.stringify(item)
          }else{
            //  为了避免 1 和 '1' 这样的情况出现在同一个key中
            key = typeof(item) + item;
          }
          return obj.hasOwnProperty(key) ? false : (obj[key] = true)
      })
      console.log(obj)
      return res
  }
复制代码

测试用例

var arr = [1,1,'1','1',0,0,'0','0',undefined,undefined,null,null,NaN,NaN,{},{},{"a":1},{"a":1},[1,2],[1,2],/a/,/a/,function(){console.log(1)},function(){console.log(1)}]
复制代码

测试结果

// 打印的辅助对象
{ number1: true,
  string1: true,
  number0: true,
  string0: true,
  undefinedundefined: true,
  null: true,
  numberNaN: true,
  '{}': true,
  '{"a":1}': true,
  '[1,2]': true,
  'functionfunction(){console.log(1)}': true }
// 打印结果
[ 1,
  '1',
  0,
  '0',
  undefined,
  null,
  NaN,
  {},
  { a: 1 },
  [ 1, 2 ],
  [Function] ]
复制代码

简单的记录一下自己的实验结果,感觉还能够改进,还在努力中。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值