声明
以下方法仅对数组值全部属于 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<l;i++){
var tmp = array[i];
deduped.indexOf(tmp) === -1 && deduped.push(tmp);
}
console.log(deduped);
// [1, 2, 3, 4, 5]
知识补充——关于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