首頁  >  文章  >  web前端  >  JavaScript數組去重的方法總結(附程式碼)

JavaScript數組去重的方法總結(附程式碼)

不言
不言轉載
2019-01-29 10:10:092945瀏覽

這篇文章帶給大家的內容是關於JavaScript陣列去重的方法總結(附程式碼),有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。

陣列去重在日常開發中的使用頻率還是較高的,也是網路上隨便一抓一大把的話題,所以,我寫這篇文章目的在於歸納和總結,既然很多人都在提的數組去重,自己到底了解多少呢。又或者是如果自己在開發上遇到了去重的需求,自己能想到更好的解決方案嗎。

這次我們來理一理怎麼做數組去重才能做得最合適,既要考慮相容性,也要考慮效能和程式碼的優雅。

我的學習路徑是模仿冴羽(github: mqyqingfeng)的學習方式,感謝像冴羽這樣優秀的人在前面領跑,我不想光看不做,所以多實踐多輸出,希望未來能走出我自己的路。

一、入門方案

function unique(origin) {
    var result = [];
    for(var i = 0; i < origin.length; i++) {
        var arrayItem = origin[i];

        for(var j= 0; j< result.length; j++) {
            var resultItem = result[j];
            
            // 如果在结果数组循环中找到了该元素,则跳出循环,进入下一个源数组元素的判断
            if(resultItem === arrayItem) {
                break;
            }
        }
        
        // 如果把结果数组循环完都没有找到该元素,就将该元素压入结果数组中
        if(j === result.length) {
            result.push(arrayItem);
        }
    }
    return result;
}

var array = [&#39;a&#39;, &#39;b&#39;, &#39;c&#39;, &#39;1&#39;, 0, &#39;c&#39;, 1, &#39;&#39;, 1, 0];
console.log(unique(array));  // ["a", "b", "c", "1", 0, 1, ""]

以上程式碼是最簡單實作陣列去重的方式,優點在於相容性極佳,缺點就是兩次for 循環,時間複雜度為O(n ^2),性能較差。

二、陣列的 indexOf 屬性

陣列中的 indexOf 屬性是 ES5 的規範,只有 IE8 及更早版本不支援此方法。相對來說,如果你不需要相容 IE8 的話,盡量用 indexOf 來判斷一個元素是否在陣列中。

function unique(origin){
    var result = [];
    for(var i = 0; i< origin.length; i++) {
        var item = origin[i];
        if(result.indexOf(item) === -1) {
            result.push(item);
        }
    }
    return result;
}

三、數組的 filter 屬性

數組的 filter() 方法建立一個新的數組,新數組中的元素是透過檢查指定數組中符合條件的所有元素。

filter 的回呼有三個參數,其中第三個參數是目前元素屬於的陣列對象,這樣我們就可以繼續利用 indexOf 屬性啦。

function unique(origin) {
    var result = origin.filter(function (item, index, array){
        // 获取元素在源数组的位置,只返回那些索引等于当前元素索引的值。
        return array.indexOf(item) === index;
    });
    return result;
}

filter 相容到 IE9, 這種方法沒有 for 循環,主要利用了 filter 和 indexOf 屬性,所以程式碼相對比較優雅。

四、利用Object 的key value

function unique(origin) {
    var result = [];
    var hashTable = {};
    for(var i = 0; i< origin.length; i++) {
        // 如果键对应的值,为真,意味着对象的键中已经有重复的键了。
        if(!hashTable[origin[i]]) {
        // 将元素作为对象的键,默认键对应的值为 true, 
            hashTable[origin[i]] = true;
            
            // 如果对象中没有这个键,则将这个元素放入结果数组中去。
            result.push(origin[i]);
        }
    }
    return result;
}

這種方案的事件複雜度為O(n), 但是物件的鍵,預設是字串類型,這代表什麼呢,數字1 和字串'1',在鍵中是相等的,所以,上面這種方法不適合字串和數字混合的去重。

所以我們將元素的類型也放入物件的鍵中:

function unique(origin) {
    var result = [];
    var hashTable = {};
    for(var i = 0; i< origin.length; i++) {
        var current = origin[i];
        // 字符串拼接元素的类型和元素
        var key = typeof(current) + current;
        if(!hashTable[key]) {
            hashTable[key] = true;
            result.push(current);
        }
    }
    return result;
}

五、陣列的sort 方法

function unique(origin) {
    return origin.concat.sort().filter(function(item, index, array) {
        // !index 表示第 0 个元素应该被返回。
        return !index || item !== origin[index-1]
    })
}

function unique(array) {
    array.sort(); // 排序字符串
    array.sort(function(a, b) {
        return a-b; // 排序数字
    })
    
    for(let i=0; i<array.length; i++) {
        if(array[i] === array[i+1]) {
            array.splice(i, 1);
            i--; // 应该将前一个数删除,而不是删除后一个数。是因为元素被删除之后,后面元素的索引会迁移,所以要 i--;
        }
    }
    return array;
}

sort 方法的優點在於利用了排序,返回後一個和前一個不相等的元素。比較簡潔和直觀。缺點在於改變了元素的本來的排序位置。

六、ES6 Set

ES6 提供了新的資料結構 Set,它類似數組,但是成員的值都是唯一的,沒有重複的值。在 Set 加入值的時候,不會發生型別轉變,所以 5 和 '5' 是兩個不同的值。 Set內部判斷兩個值是否相同,用的是類似"==="的演算法,但差異是,在set內部認為NaN 等於NaN ;

Set 可以轉換為數組,所以很容易實現去重

function unique(origin) {
    return Array.from(new Set(origin));
}

七、ES6 Map

ES6 新增了Map 資料結果,透過has 和set 方法就能很方便的對前面的object key value 方案進行最佳化。

function unique(origin){
    const map = new Map()
    return origin.filter((item) => !map.has(item) && map.set(item, true))
}

八、型別判斷

一些常見的資料型別是===indexOf 是無法偵測的,舉例:

console.log({} === {})  // false;

console.log(NaN === NaN)  // false;

console.log(/a/ === /a/);  // false;

console.log(1 === new String('1'))  // false;

var arr = [NaN];
console.log(arr.indexOf(NaN)); // -1

所以在判斷的時候,如果資料裡有NaN 和物件時要避免使用indexOf===;

前面Set 那裡說過了,所以Set 方法是可以去重NaN的。

總結

資料去重在網路上已經看煩了,但還是想專門寫一篇文章來實踐和總結,能在工作中多幾個思路也是極好的。感謝那些熱愛分享和喜歡輸出的人。

#

以上是JavaScript數組去重的方法總結(附程式碼)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:segmentfault.com。如有侵權,請聯絡admin@php.cn刪除