聲明
以下方法僅對數(shù)組值全部屬于 primitive data type 的情況有效。
ES6
方法一: Set數(shù)據(jù)結(jié)構(gòu) + Array.from靜態(tài)方法
ES6中新增了Set數(shù)據(jù)結(jié)構(gòu),類似于數(shù)組,但是它的成員都是唯一的 ,其構(gòu)造函數(shù)可以接受一個數(shù)組作為參數(shù),如:
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數(shù)據(jù)結(jié)構(gòu) + 擴展語法(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
方法三: 箭頭函數(shù)+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]
知識補充——關(guān)于indexOf
關(guān)于瀏覽器兼容性
在 IE6-8 下,數(shù)組的 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
}
關(guān)于性能——時間復(fù)雜度
如果說利用 set 數(shù)據(jù)結(jié)構(gòu)是一種作弊的方式,那么用 indexOf 就是一種相對低下性能的方式,因為 indexOf 的底層也是一次遍歷。嵌套循環(huán)會讓追求性能極致的人感覺不爽。
① arr 遍歷push 到新數(shù)組
② 其中每循環(huán)一次調(diào)用數(shù)組的 indexOf 方法,又會是一次遍歷
所以,相當(dāng)于兩次循環(huán)嵌套,遍歷復(fù)雜度為O(n2)
這種情況下,為追求性能,更好的實現(xiàn)方式為:利用對象 key 的唯一性處理。首先將數(shù)組轉(zhuǎn)換為對象,其次將對象轉(zhuǎn)換為去重后的數(shù)組。
比如:
var songs = [
{name:"都選C",artist:"大鵬"},
{name:"都選C",artist:"大鵬"},
{name:"塑料袋",artist:"喬杉"},
{name:"塑料袋",artist:"喬杉"},
{artist:"喬杉",name:"塑料袋"}
];
function unique(songs){
let result = {};
let finalResult=[];
// 數(shù)組轉(zhuǎn)換為對象,利用對象key的唯一性去重
songs.forEach(function(song, i){
result[song.name]=song;
})
// 將對象還原為去重后的數(shù)組
Object.keys(result).forEach(function(key, i){
finalResult.push(result[key]);
})
return finalResult;
}
console.log(unique(songs));
// 注明:偷了個懶 forEach 的性能比 for 循環(huán)慢好多。
// 參考:https://github.com/jawil/blog/issues/2
2017-11-16 更新。實際上這個用了至少兩次循環(huán)(雖然不是循環(huán)嵌套),但仍然是低效的。因為最簡單的數(shù)組去重只需要用一層循環(huán)即可。
更為復(fù)雜的案例可以看筆者寫的這個demo