不賣關子,直入主題es6
數組去重,最早想到的即是依次遍歷數組,在已遍歷的元素中查找是否存在當前數組元素,重點是用什麼存放已遍歷的數組,以及如何區分當前元素是否已存在算法
因爲下面會用到indexOf()的方法,它是ES5語法,低版本會存在兼容,先應添加對應的polyfillsegmentfault
Array.prototype.indexOf = Array.prototype.indexOf || function (searchElement, fromIndex) { var index = -1; fromIndex = fromIndex * 1 || 0; for (var k = 0, length = this.length; k < length; k++) { if (k >= fromIndex && this[k] === searchElement) { index = k; break; } } return index; };
1.數組存放,indexOf()判斷數組
遍歷數組,創建新數組,利用indexOf判斷是否存在於新數組中,不存在則push到新數組,最後返回新數組函數
Array.prototype.unique = function() { var n = []; // 存放已遍歷的知足條件的元素 for (var i = 0; i < this.length; i++) { // indexOf()判斷當前元素是否已存在 if (n.indexOf(this[i]) == -1) n.push(this[i]); } return n; }
下面是一個思想基本相同的變相版本性能
Array.prototype.unique = function() { // 建立一個新的臨時數組,而且把當前數組的第一元素存入到數組中 var n = [this[0]]; // 從第二項開始遍歷 for (var i = 1; i < this.length; i++) { // 若是當前數組的第i項在當前數組中第一次出現的位置不是i,那麼表示第i項是重複的,忽略掉,不然存入結果數組 if (this.indexOf(this[i]) == i) n.push(this[i]); } return n; }
JS引擎在實現indexOf()的時候會遍歷數組直到找到目標爲止,此函數會浪費掉不少時間。全部這兩種方式都不是最優的解決方式this
// es5簡化版 Array.prototype.unique = function() { return this.filter((v, i) => this.indexOf(v) === i) } // es6簡化版 Array.prototype.unique = function() { return Array.from(new Set(this)); } // 或 Array.prototype.unique = function() { return [...new Set(this)]; }
2.對象存放,哈希算法(映射)判斷es5
Array.prototype.unique = function() { // n爲hash表,r爲臨時數組 var n = {}, r = []; for (var i = 0; i < this.length; i++) { // 若是hash表中沒有當前項 if (!n[this[i]]) { // 存入hash表 n[this[i]] = true; // 把當前數組的當前項push到臨時數組裏面 r.push(this[i]); } } return r; }
但從耗時的角度來說,這是最優的一種解決方式。可是從內存佔用角度來講,這並非最優的,由於多了一個hash表。這就是所謂的空間換時間prototype
3.先排序,後比較code
這種方式最大的優點就是排序後的比較次數變少,可是排序的過程也有性能消耗,應權衡使用
Array.prototype.unique = function() { this.sort(); var re = [this[0]]; for (var i = 1; i < this.length; i++) { if (this[i] !== re[re.length - 1]) { re.push(this[i]); } } return re; }
這個方法的思路是先把數組排序,而後比較相鄰的兩個值。排序的時候用的JS原生的sort()方法,JS引擎內部應該是用的快速排序吧。這種方式比使用indexOf()的通常姿式要快,比使用hash表的最快姿式要慢,可是佔用內存要少
主要內容來自:數組去重的正確編寫姿式