JS中去重方法的探討

說到去重有很多的實現,在ES6下根本不是問題:

let array=[1,2,3,4,1,2,3,4]
let result=null

// 利用 indexOf 只會返回第一次匹配結果的特性,過濾出第一次出現的項
result=array.filter((value,i)=>array.indexOf(value)===i)

// Set 對象數據結構決定了其元素的唯一性,再按需通過擴展符號將其轉為數組
result=[...new Set(array)]

然而在ES6之前,兼顧性能的習慣性思路是基于 for 的遍歷實現,copy 一個新的集合并與原始集合做遍歷、比對,類似如下這種實現方法:

var uniq1=function(arr){
    var temp=[],
        item,
        i,n;

    for(i=0;i<arr.length;i+=1){ // 開始去重
        item=arr[i];
        temp.push(item);
        for(n=0;n<temp.length;n+=1){
            if(item===temp[n-1]){ // 如temp與arr中的元素重復則刪除
                temp.splice(temp.length-1,1);
            }
        }
    }
    return temp;
};

上面這個例子會創建一個臨時的空數組對象,在將元素逐個放入其中時與前一個元素作比對,如果值相同則從臨時數組中剔除,直至遍歷完所有比對對象……這個方法盡可能的優化了性能,但是出現了嵌套循環,代碼實現邏輯復雜、對部分閱讀者并不友好對嗎?下面介紹一種或許可以減壓并且性能表現不俗的實現方法。

先說說思路,我們習慣對數組元素逐一比較后取得不重復值的方式來實現去重,這讓編程者思維局限在數組里。其實js世界為我們提供了現成的去重偏方——對象{},因為對象的鍵名是唯一的,我們利用這一特性,把值作為對象的鍵名就可以實現去重,于是:

var uniq2=function(arr){
    var i,temp=[],
        key,newArr=[];

    for(i=0;i<arr.length;i+=1){//遍歷數組,將值作為鍵名放入對象中
        temp[arr[i]] = (temp[arr[i]]+1)||1;//對象值隨便賦,用作重復次數的統計是個不錯的選擇
    }

    for(key in temp){//把生成的臨時對象轉回數組
        newArr.push(key);
    }

    return newArr;
};

邏輯清晰,效果很好。由于是直接對對象鍵名的覆蓋,無需比對重復值,循環體的運算復雜度大大減少,這在做大量數據操作時對性能的提升會很明顯,因為無論如何僅僅是對數組的一次遍歷而已。我們寫個簡單的測試得到如下結果:

測試結果1

優勢明顯!但是帶來一個新問題,我們遍歷結果發現所有的值都變成了字符串!還有,如果是對象集合的去重呢?我們知道對象的鍵名是字符串,不能直接用對象字面量,真是沒有銀彈!怎么辦?我們依舊沿襲“偷懶的作風”,用js給我們提供的現成方法JSON.stringify()把對象轉成字符串,在去重完成后用JSON.parse()方法轉回對象字面量……好吧,這太容易了,所以,我再偷下懶,完整的實現代碼就由各位自由發揮吧,很容易不是嗎。

據說寫個ES6代碼在用Babel轉換下不就好了……然而用戶需求是無止境的依然有人不放棄對<ie8的支持。并且我發現第二種方法即使加上JSON的解析,在性能上依然優于[...new Set(arr)]

測試結果2

可能這點數據量還不足以體現這種方法的巨大優勢,我們加點料再測一次:

測試結果3

完勝啊!

關于去重還有很多話題可以展開,比如算法、對結果排序的影響等,但歸根結底還是性能優化、高效處理。這是個很有趣味的主題!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 本文為阮一峰大神的《ECMAScript 6 入門》的個人版提純! babel babel負責將JS高級語法轉義,...
    Devildi已被占用閱讀 2,029評論 0 4
  • 下面不屬于ECMAScript規范的范圍的是:( )A、 數據類型B、 語法C、 DOM事件D、 內置對象和函數的...
    亓凡閱讀 3,006評論 3 9
  • 驟雨初歇,秋涼西風疏桐葉。 萬家燈滅,玉簟孤枕夜。 高位維艱,何日夫郎卸。 燭光曳,錦書將寫,落筆心怯怯。
    小木山莊的溜溜閱讀 328評論 2 8
  • 目錄[http://www.lxweimin.com/p/276212c4ad9b] 前篇[https://www...
    北雫閱讀 576評論 0 0
  • 今天分享的主題是“踢貓效應”,想必大家從字面的意思就會有點疑惑吧?為什么是踢貓了?不是踢狗,或者是獅子?大家可以腦...
    SeeOne閱讀 210評論 0 0