[js]从 ES3 到 ES6 教你如何数组去重

声明

以下方法仅对数组值全部属于 primitive data type 的情况有效。

ES6

方法一: Set数据结构 + Array.from静态方法

ES6中新增了Set数据结构,类似于数组,但是它的成员都是唯一的 ,其构造函数可以接受一个数组作为参数,如:

 let array = [1, 1, 1, 1, 2, 3, 4, 4, 5, 3];
 let set = new Set(array);
 let deduped = Array.from(set);// `deduped = de + dup(duplication) + ed`
 console.log(deduped);
 // [1, 2, 3, 4, 5]

方法二:Set数据结构 + 扩展语法(spread syntax)

let array = [1, 1, 1, 1, 2, 3, 4, 4, 5, 3];
let deduped = [...new Set(array)];
console.log(deduped);
 // [1, 2, 3, 4, 5]

注意扩展语法对所有可遍历对象均有效

let obj = {'key1': 'value1'};
let array = [...obj]; 
// TypeError: obj is not iterable

方法三: 箭头函数+es5语法(filter, indexOf)

let array = [1, 1, 1, 1, 2, 3, 4, 4, 5, 3];
let deduped = array.filter((el,i,arr) => arr.indexOf(el) === i);
console.log(deduped);
 // [1, 2, 3, 4, 5]

ES5

var array = [1, 1, 1, 1, 2, 3, 4, 4, 5, 3];
var deduped = array.filter(function(el,i,arr) {
    return arr.indexOf(el) === i;
})
console.log(deduped);
 // [1, 2, 3, 4, 5]

lt_ES5

var array = [1, 1, 1, 1, 2, 3, 4, 4, 5, 3,[1,2],[3,4]];
var deduped = [];
for(var i=0, l=array.length;i

知识补充——关于indexOf

关于浏览器兼容性

在 IE6-8 下,数组的 indexOf 方法还不存在。
所以如果需要兼容 IE6-8,得自己造一个轮子:

var indexOf = [].indexOf ?
    function(arr, item) {
      return arr.indexOf(item)
    } :
    function indexOf(arr, item) {
      for (var i = 0; i < arr.length; i++) {
        if (arr[i] === item) {
          return i
        }
      }
      return -1
    }

关于性能——时间复杂度

如果说利用 set 数据结构是一种作弊的方式,那么用 indexOf 就是一种相对低下性能的方式,因为 indexOf 的底层也是一次遍历。嵌套循环会让追求性能极致的人感觉不爽。

① arr 遍历push 到新数组
② 其中每循环一次调用数组的 indexOf 方法,又会是一次遍历
所以,相当于两次循环嵌套,遍历复杂度为O(n2)

这种情况下,为追求性能,更好的实现方式为:利用对象 key 的唯一性处理。首先将数组转换为对象,其次将对象转换为去重后的数组。
比如:

var songs = [
         {name:"都选C",artist:"大鹏"},
         {name:"都选C",artist:"大鹏"},
         {name:"塑料袋",artist:"乔杉"},
         {name:"塑料袋",artist:"乔杉"},
         {artist:"乔杉",name:"塑料袋"}
     ];

function unique(songs){
  let result = {};
  let finalResult=[];
  // 数组转换为对象,利用对象key的唯一性去重
  songs.forEach(function(song, i){
    result[song.name]=song;
  })
  // 将对象还原为去重后的数组
  Object.keys(result).forEach(function(key, i){
    finalResult.push(result[key]);
  })
  
  return finalResult;
}

console.log(unique(songs));

// 注明:偷了个懒 forEach 的性能比 for 循环慢好多。
// 参考:https://github.com/jawil/blog/issues/2

2017-11-16 更新。实际上这个用了至少两次循环(虽然不是循环嵌套),但仍然是低效的。因为最简单的数组去重只需要用一层循环即可。

更为复杂的案例可以看笔者写的这个demo

参考资料

https://github.com/lifesinger/blog/issues/113

你可能感兴趣的:([js]从 ES3 到 ES6 教你如何数组去重)