JavaScript實現(xiàn)數(shù)組去重的20種方法總結(jié)
1.easy模式
此時我們有一個極其簡單的數(shù)組,它可能包含也不包含重復項。我們需要刪除重復項并將唯一值放入新數(shù)組中。
const names = ["a","b","c","d","e","a","b"];
new Set
時間復雜度:O(n^2), 但擴展符運算符耗費時間有點多,一般推薦
最簡單的,new Set去重
let newNames = [...new Set(names)]
時間復雜度:O(n^2), 比擴展運算符還費勁,一般推薦
let newNames = Array.from(new Set(names))
new Map
時間復雜度:O(n^2), 一般推薦 通過new Map原型上的方法去重。
function dealArr (a) {
let newArr = []
let map = new Map()
for(let i = 0;i<a.length;i++){
if (!map.has(a[i])) {
map.set(a[i], true)
newArr.push(a[i])
}
};
return newArr
}
笨蛋雙重for循壞
感覺實在沒什么好說的,就純暴力去重
function dealArr(a){
let len = a.length;
for(let i = 0; i < len; i++) for(let j = i + 1; j < len; j++)
if(a[j] == a[i]){
a.splice(j,1);
j--;
len--;
}
return a;
}
function dealArr(a) {
let b = [];
for (let i = a.length - 1; i >= 0; i--) {
for (let j = a.length - 1; j >= 0; j--) {
if (a[i] == a[j] && i != j) {
delete a[j];
}
}
if (a[i] != undefined) b.push(a[i]);
}
return b;
}
單for循壞
時間復雜度:O(n), 它真的太快了,它是所有種類的方法里最快的,大伙可以試一試, 推薦
for循壞+hash查找
function dealArr(a) {
let obj = {};
let out = [];
let len = a.length;
let j = 0;
for(let i = 0; i < len; i++) {
let item = a[i];
if(obj[item] !== 1) {
obj[item] = 1;
out[j++] = item;
}
}
return out;
}
下面這種會快一點。
function dealArr(a) {
obj = {};
for (let i = 0; i < a.length; i++) {
obj[a[i]] = true;
}
return Object.keys(obj);
}
for and includes
時間復雜度:O(n^2), 不推薦
for循環(huán) + includes判斷,includes會循壞到找到為止或者全部,所以挺慢的。
function dealArr(a) {
let newArr = [];
let j = 0;
for (i = 0; i < a.length; i++) {
let current = a[i];
if (!newArr.includes(current)) newArr[j++] = current;
}
return newArr;
}
for and indexOf
時間復雜度:O(n^2), 不推薦
for循環(huán) + indexof查找,indexOf會找到第一個為止或者全部。
function dealArr(a) {
let newArr = [];
let j = 0;
for (i = 0; i < a.length; i++) {
let current = a[i];
if (newArr.indexOf(current) < 0) newArr[j++] = current;
}
return newArr;
}
for and lastIndexOf
時間復雜度:O(n^2), 不推薦
沒啥好說的,其實和indexOf一樣只是正反序查找的區(qū)別而已,問就是慢
function dealArr(a) {
let newArr = [];
let j = 0;
for (i = 0; i < a.length; i++) {
let current = a[i];
if (newArr.lastIndexOf(current) < 0) newArr[j++] = current;
}
return newArr;
}
for and newArr
相比哈希也慢
一個新數(shù)組和原數(shù)組對比,不同則放在新數(shù)組,最后返回。
function dealArr(a) {
let newArr = [a[0]];
for (let i = 1; i < a.length; i++) {
let repeat = false;
for (let j = 0; j < newArr.length; j++) {
if (a[i] === newArr[j]) {
repeat = true;
break;
}
}
if (!repeat) {
newArr.push(a[i]);
}
}
return newArr;
}for and sort
想想有什么問題
先將原數(shù)組排序,再與相鄰的進行比較,如果不同則存入新數(shù)組。
function dealArr(a) {
let formArr = a.sort()
let newArr=[formArr[0]]
for (let i = 1; i < formArr.length; i++) {
if (formArr[i]!==formArr[i-1]) newArr.push(formArr[i])
}
return newArr
}
splice
O(n^2),特別慢
function dealArr(arr) {
let i,j,len = arr.length;
for (i = 0; i < len; i++) {
for (j = i + 1; j < len; j++) {
if (arr[i] == arr[j]) {
arr.splice(j, 1);
len--;
j--;
}
}
}
return arr;
}
filter and indexOf
時間復雜度:O(n^2)一般推薦
filter的本質(zhì)相當于,在每一個元素上添加檢查,檢查該元素在數(shù)組中的第一個位置是否等于當前位置,indexof是找到第一個符合條件的元素。重復元素在數(shù)組里的位置是與找到的第一個不同的。
let newNames = names.filter(function(item, index) {
return names.indexOf(item) == index;
})
但其實上述方法不是很好,因為可能你會操作到原數(shù)組,導致原數(shù)據(jù)變化,那么我們可以直接用filter的第三個參數(shù)來做這件事,保證原數(shù)據(jù)的不可變性。
let newNames = names.filter(function(item, index, self) {
return self.indexOf(item) == index;
})
filter and sort
時間復雜度:O(n)- O(n^2)不推薦
就是先對數(shù)組進行排序,然后刪除與前一個元素相等的每個元素。大家也可以想想這方法有啥問題。提示:排序。
let newNames = a.sort().filter(function(item, index, self) {
return !index || item != self[index - 1];
});
reduce
實在是太慢了,不推薦
reduce果然是js里最完美的api。
let newNames = names.reduce(function(a,b){
if (a.indexOf(b) < 0 ) a.push(b);
return a;
},[]);
笨蛋hashMap
時間復雜度:O(n)一般
這個方法有點笨,通過哈希表查找來fiter,大伙可以想一想缺陷是什么。(提示:對象,key。 測試用例: [1, '1']。)
function dealArr(a) {
let seen = {};
return a.filter(function(item) {
return seen.hasOwnProperty(item) ? false : (seen[item] = true);
});
}
2.Normal模式
easy模式下我們都只處理一些基數(shù)組,接下來我們處理一下數(shù)組對象+基數(shù)組。
一般聰明的hashMap
一般聰明的hash,大伙看到這應該能明白上面的問題是什么了吧。經(jīng)過一點點優(yōu)化,我們對原始值和引用對象分開處理,到這它已經(jīng)有了處理對象引用重復的能力了,但是它確實還不夠聰明。
就像這樣:

function dealArr(a) {
let prims = {"boolean":{}, "number":{}, "string":{}}, objs = [];
return a.filter(function(item) {
let type = typeof item;
if(type in prims)
return prims[type].hasOwnProperty(item) ? false : (prims[type][item] = true);
else
return objs.indexOf(item) >= 0 ? false : objs.push(item);
});
}
聰明的hashMap
我們有時候可以寫一個通用的函數(shù),通過回調(diào)函數(shù)來優(yōu)雅的完成過濾,比如這樣!

大家可以思考一下為什么JSON.stringify,能完成過濾。
function dealArrByBey(a, key) {
let obj = {};
return a.filter(function(item) {
let k = key(item);
return obj.hasOwnProperty(k) ? false : (obj[k] = true);
})
}
稍微炫一點
但這都es6了還這么玩不太合適,這樣會好看一些。

可以看到過濾了后面的b.
function dealArrByBey(a, key) {
let obj = new Set();
return a.filter(item => {
let k = key(item);
return obj.has(k) ? false : obj.add(k);
});
}
特別炫
感覺這么寫就特別開心了,雖然可讀性不好,而且也不是很快,但它很帥啊。但這三種方法,是有點區(qū)別的,上面兩種方法是保留第一個,過濾掉后面的,而這種方法保留的是最后一個,大伙可以思考一下為什么。
function dealArrByBey(a, key) {
return [
...new Map(
a.map(x => [key(x), x])
).values()
]
}
3.hard模式
珂里化 + 鏈式調(diào)用
em,都寫到這了,我們可以再進階再抽象一下,讓我們的去重也可以寫成一個非常抽象的鏈式調(diào)用。多重箭頭函數(shù)其實就是函數(shù)珂里化的語法糖(fn(a,b,c)改造成fn(a)(b)(c)),讓我們完成一個參數(shù)對齊。

const apply = f => a => f(a);
const flip = f => b => a => f(a) (b);
const uncurry = f => (a, b) => f(a) (b);
const push = x => xs => (xs.push(x), xs);
const fold = f => acc => xs => xs.reduce(uncurry(f), acc);
const some = f => xs => xs.some(apply(f));
const dealArrByFn = f => fold(
acc => x => some(f(x)) (acc)
? acc
: push(x) (acc)
) ([]);
const eq = y => x => x === y;
dealArrByFn(eq)(names)到此這篇關(guān)于JavaScript實現(xiàn)數(shù)組去重的20種方法總結(jié)的文章就介紹到這了,更多相關(guān)JavaScript數(shù)組去重內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
json對象轉(zhuǎn)為字符串,當做參數(shù)傳遞時加密解密的實現(xiàn)方法
下面小編就為大家?guī)硪黄猨son對象轉(zhuǎn)為字符串,當做參數(shù)傳遞時加密解密的實現(xiàn)方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-06-06
JavaScript使用BigInt處理超大數(shù)值全指南
在JavaScript開發(fā)中,數(shù)值處理看似簡單,卻隱藏著一個容易被忽視的陷阱 —— 數(shù)值精度限制,面對超過安全整數(shù)范圍的超大數(shù)值時,傳統(tǒng)的 Number 類型往往力不從心,而BigInt的出現(xiàn)正是為了解決這一痛點,本文將深入探討JavaScript數(shù)值處理的困境、BigInt的應用場景及最佳實踐2025-07-07

