需求描述:爲Array類型添加公共方法Unique,去掉給定數組中的重複元素。
五種方法:
/*方法一*/
//爲Array類型的prototype對象添加unique1方法
Array.prototype.unique1=function(){
//遍歷當前數組對象中的每個元素,同時創建新空數組對象,保存在變量n中
for(var i=0,n=[];i<this.length;i++){
n.indexOf(this[i])==-1&&n.push(this[i]);
}
return n;
}
/*方法二*/
//爲Array類型的prototype對象添加unique2方法
Array.prototype.unique2=function(){
//遍歷當前數組中每個元素,同時創建一個hash對象和一個結果數組
for(var i=0,hash={},r=[];i<this.length;i++){
!hash[this[i]]&&(hash[this[i]]=null,r.push(this[i]));
}
return r;
}
/*方法三*/
//爲Array類型的prototype對象添加unique3方法
Array.prototype.unique3=function(){
//先將數組元素默認按升序排列
this.sort();
//遍歷數組中每個元素,同時創建結果數組r,先放入原數組第一個元素。
for(var i=1,r=[this[0]];i<this.length;i++){
//用原數組當前元素和結果數組最後一個元素比較,如果不相等,就將原數組當前元素壓入結果數組
this[i]!==r[r.length-1]&&r.push(this[i]);
}
return r;
};
/*方法四:*/
//爲Array類型的prototype對象添加unique4方法
Array.prototype.unique4=function(){
//以空數組作爲基礎,依次迭代處理數組中每個元素。如果當前元素c在p數組中未出現過,則將當前元素c壓入p數組。
return this.reduce(function(prev, curr) {
prev.indexOf(curr)<0&&prev.push(curr);
return prev;
}, []);
};
/*方法五:*/
//爲Array類型的prototype對象添加unique5方法
Array.prototype.unique5 = function () {
//先將數組排序,再用兩個逗號拼接數組元素,再用正則表達式將多個逗號分隔的相同的子字符串替換爲僅剩一個第一個。最後按兩個逗號爲分隔,將字符串再切割成數組。
return this.sort().join(",,").replace(/(,|^)([^,]+)(,,\2)+(,|$)/g,"$1$2$4").split(",,");
}
/*測試代碼:*/
window.οnlοad=function(){
//獲得輸出結果的div
var out=document.getElementById("out");
//隨機生成10000個0~10000之間的隨機數,放入數組arr中
for(var i=0,arr=[];i<10000;i++){
arr.push(Math.floor(Math.random()*10000));
}
//獲得開始時間:
var start=new Date();
//調用數組類型的去重複方法1,獲得新數組保存在變量re中
var re=arr.unique1();
//獲得結束時間:
var end=new Date();
//在控制檯輸出數組內容:
console.log(re);
//在輸出div中寫入方法和耗時
out.innerHTML+="方法1 耗時 "+(end-start)+" ms<br>";
//獲得開始時間:
start=new Date();
//調用數組類型的去重複方法2,獲得新數組保存在變量re中
re=arr.unique2();
//獲得結束時間:
end=new Date();
//在控制檯輸出數組內容:
console.log(re);
//在輸出div中寫入方法和耗時
out.innerHTML+="方法2 耗時 "+(end-start)+" ms<br>";
//獲得開始時間:
start=new Date();
//調用數組類型的去重複方法3,獲得新數組保存在變量re中
re=arr.unique3();
//獲得結束時間:
end=new Date();
//在控制檯輸出數組內容:
console.log(re);
//在輸出div中寫入方法和耗時
out.innerHTML+="方法3 耗時 "+(end-start)+" ms<br>";
//獲得開始時間:
start=new Date();
//調用數組類型的去重複方法4,獲得新數組保存在變量re中
re=arr.unique4();
//獲得結束時間:
end=new Date();
//在控制檯輸出數組內容:
console.log(re);
//在輸出div中寫入方法和耗時
out.innerHTML+="方法4 耗時 "+(end-start)+" ms<br>";
//獲得開始時間:
start=new Date();
//調用數組類型的去重複方法5,獲得新數組保存在變量re中
re=arr.unique5();
//獲得結束時間:
end=new Date();
//在控制檯輸出數組內容:
console.log(re);
//在輸出div中寫入方法和耗時
out.innerHTML+="方法5 耗時 "+(end-start)+" ms<br>";
}
測試代碼:
/*測試代碼:*/
window.οnlοad=function(){
… …
//在輸出div中寫入方法和耗時
out.innerHTML+="方法1 耗時 "+(end-start)+" ms<br>";
//獲得開始時間:
start=new Date();
//調用數組類型的去重複方法2,獲得新數組保存在變量re中
re=arr.unique2();
//獲得結束時間:
end=new Date();
//在控制檯輸出數組內容:
console.log(re);
//在輸出div中寫入方法和耗時
out.innerHTML+="方法2 耗時 "+(end-start)+" ms<br>";
}
對比前兩種方法:明顯第二種方法效率更高。主要原因:數組類型的indexOf方法其實也需要遍歷數組中每個元素,才能找到匹配的元素。這就大幅增加了循環和比較的次數。而方法二中利用了JavaScript語言中對象底層其實是hash數組的特性。hash數組中,按照key查找元素,無需遍歷。所以自然在循環次數上優於方法一。但是方法二卻多創建了一個對象。多佔用了空間,卻換來了執行效率上的優化,這種現象也稱爲用空間換時間。
方法三比方法二效率稍低。因爲方法三需要先對數組排序。無論採用何種方法排序,都會增加遍歷和比較的次數。但即使如此,方法三遠優於方法一。因爲數組的sort方法採用的排序算法通常都經過了特別的優化,比indexOf這樣的遍歷方法效率要高。
方法五的執行效率與方法三相當。因爲都採用了sort方法先排序再處理。另外,由此還可看出正則表達式處理字符串的效率和數組遍歷的效率幾乎相當。可見正則表達式的效率也是非常高的。
結論:查找最快的數據結構是hash數組。經常用於統計元素數量,去除重複元素等需要反覆遍歷和比較的操作中。而indexOf方法的效率不高,不推薦作爲首選方法。
ES6中:
// 去除數組的重複成員
[...new Set(array)]