雖然演算法在前端開發中很少會得以使用,但是瞭解常用的演算法,熟悉各種演算法的效能和優劣,將會讓你在前端的道路上走的更遠。
前言
文中所有程式碼位於位於此程式碼倉庫中,大家可以下載程式碼進行學習、推敲和改進。另,如果覺得這些用心推敲的程式碼對你有幫助的話,歡迎 star 一下程式碼倉庫,眾籌博主的小星星。
另外,本文中使用如下函式對程式碼進行效能測試:
module.exports = async function getFnRunTime(fn) {
let startTime = Date.now(), endTime;
let result = await fn();
endTime = Date.now();
console.log(`total time:${endTime-startTime}ms`,
'test array\'length:' + len,
result.length
);
}
複製程式碼
為了衡量效能,我們引入程式碼時間複雜度的概念,用大寫O()來表現演算法時間複雜度的記法,我們稱之為大O記法。一般情況下,隨著n的增大,T(n)增長最慢的演算法為最優演算法。
1.雙重for迴圈去重
如果有相同的值則跳過,不相同則push進陣列
function distinct1(arr = testArr) {
let result = [],
len = arr && arr.length;
for (let i=0; i< len; i++) {
for (let j=i+1; j< len; j++) {
if (arr[i] === arr[j]) {
j = ++i;
}
}
result.push(arr[i])
}
return result
}
複製程式碼
由於使用了雙層for迴圈,根據程式碼可知時間複雜度為O(n^2),用測試函式測的19815條資料的去重時間為:7-8ms;
2.利用indexOf和forEach/for迴圈去重
function distinct2(arr = testArr) {
let result = [];
arr.forEach((v, i, array) => {
array.indexOf(v, i+1) === -1 && result.push(v)
});
return result
}
複製程式碼
可以看到該方法的程式碼很簡潔,時間複雜度為O(n),但是indexOf會進行額外的效能消耗,測試相同的資料耗時為:4-5ms
3.物件法
通過利用物件建名的唯一性去去重
function distinct3(arr = testArr) {
let result = [], resultObj = {}, len = arr.length;
for(let i=0; i< len; i++) {
let val = arr[i],
type = typeof val;
if(!resultObj[val]) {
result.push(val);
resultObj[val] = [type];
} else if(!resultObj[val].indexOf(type) < 0) {
result.push(val);
resultObj[val] = [type];
}
}
return result
}
複製程式碼
該方法很快,時間複雜度為O(n),但是由於會多建立一個物件,會帶來額外的記憶體開銷,尤其是資料量大的情景下,測試相同的資料耗時為:5ms
4.filter去重方法一
利用filter和indexOf來查詢
function distinct4(arr = testArr) {
return arr.filter((v, i, array) => array.indexOf(v, i+1) < 0)
}
複製程式碼
該方法也很簡潔,測試相同的資料耗時為:4-5ms,關鍵優化點是利用indexOf的第二個引數去避免不必要的查詢。
5.filter去重方法二
和方法4的區別是利用陣列的索引的唯一性來去重
function distinct5(arr = testArr) {
return arr.filter((v, i, array) => array.indexOf(v) === i)
}
複製程式碼
該方法同4,但是效能遠不如方法4,因為陣列每次呼叫indexOf都會重新查詢整個陣列,但這是必須要做的操作,否則就不能利用陣列索引的唯一性了。耗時:16ms(小夥伴們都驚呆了)
6.利用es6的set方法
function distinct6(arr = testArr) {
return [...new Set(arr)]
}
複製程式碼
此方法耗時1ms,但是侷限性很大,針對相同型別的資料很快,但是不同型別的資料去重,將非常慢,這涉及到js相關的底層知識,這裡就先不介紹了,後期需要的話可以專門上一篇文章介紹~
好啦,其實陣列去重有很多種方法,只有你想不到的,沒有實現不了的,如果你有更好更快的方法,歡迎一起交流探討哦~
我們組建的vue-react-小程式-node交流學習群,已經有數百位各企業的前端夥伴加入,歡迎大家關注 趣談前端公眾號,加入前端大家庭,一起探索前端的邊界