首頁 web前端 js教程 JavaScript的陣列去重方法

JavaScript的陣列去重方法

Nov 27, 2017 am 09:24 AM
javascript js 陣列

我們都知道不同程式語言都有陣列去重,這篇文章我們就講述JavaScript陣列去重,希望能幫助大家。

雙層循環

也許我們首先想到的是使用indexOf 來循環判斷一遍,但在這個方法之前,讓我們先看看最原始的方法:

var array = [1, 1, '1', '1'];function unique(array) {    // res用来存储结果
    var res = [];    for (var i = 0, arrayLen = array.length; i < arrayLen; i++) {        for (var j = 0, resLen = res.length; j < resLen; j++ ) {            if (array[i] === res[j]) {                break;
            }
        }        // 如果array[i]是唯一的,那么执行完循环,j等于resLen
        if (j === resLen) {
            res.push(array[i])
        }
    }    return res;
}console.log(unique(array)); // [1, "1"]
登入後複製

在這個方法中,我們使用循環嵌套,最外層循環array,裡面循環res,如果array[i] 的值跟res[j] 的值相等,就跳出循環,如果都不等於,表示元素是唯一的,這時候j 的值就會等於res 的長度,根據這個特點來判斷,將值加進res。

看起來很簡單吧,之所以要講一講這個方法,是因為------相容性好!

indexOf

我們可以用indexOf 簡化內層的循環:

var array = [1, 1, &#39;1&#39;];function unique(array) {    var res = [];    for (var i = 0, len = array.length; i < len; i++) {        var current = array[i];        if (res.indexOf(current) === -1) {
            res.push(current)
        }
    }    return res;
}console.log(unique(array));
登入後複製

排序後去重

試想我們先將要去重的陣列使用sort方法排序後,相同的值就會被排在一起,然後我們就可以只判斷當前元素與上一個元素是否相同,相同就說明重複,不相同就添加進res,讓我們寫個demo:

var array = [1, 1, &#39;1&#39;];function unique(array) {    var res = [];    var sortedArray = array.concat().sort();    var seen;    for (var i = 0, len = sortedArray.length; i < len; i++) {        // 如果是第一个元素或者相邻的元素不相同
        if (!i || seen !== sortedArray[i]) {
            res.push(sortedArray[i])
        }
        seen = sortedArray[i];
    }    return res;
}console.log(unique(array));
登入後複製

如果我們對一個已經排好序的陣列去重,這種方法效率肯定高於使用indexOf。

unique API

知道了這兩種方法後,我們可以去嘗試寫一個名為unique 的工具函數,我們根據一個參數isSorted 判斷傳入的陣列是否是重複的,如果為true,我們就判斷相鄰元素是否相同,如果為false,我們就使用indexOf 進行判斷

var array1 = [1, 2, &#39;1&#39;, 2, 1];var array2 = [1, 1, &#39;1&#39;, 2, 2];// 第一版function unique(array, isSorted) {    var res = [];    var seen = [];    for (var i = 0, len = array.length; i < len; i++) {        var value = array[i];        if (isSorted) {            if (!i || seen !== value) {
                res.push(value)
            }
            seen = value;
        }        else if (res.indexOf(value) === -1) {
            res.push(value);
        }        
    }    return res;
}console.log(unique(array1)); // [1, 2, "1"]console.log(unique(array2, true)); // [1, "1", 2]
登入後複製

優化

儘管unqique 已經可以試下去重功能,但是為了讓這個API 更強大,我們來考慮一個需求:

新需求:字母的大小寫視為一致,例如'a'和'A',保留一個就可以了!

雖然我們可以先處理數組中的所有數據,比如將所有的字母轉成小寫,然後再傳入unique函數,但是有沒有方法可以省掉處理數組的這一遍循環,直接就在去重的循環中做呢?讓我們去完成這個需求:

var array3 = [1, 1, &#39;a&#39;, &#39;A&#39;, 2, 2];// 第二版// iteratee 英文释义:迭代 重复function unique(array, isSorted, iteratee) {    var res = [];    var seen = [];    for (var i = 0, len = array.length; i < len; i++) {        var value = array[i];        var computed = iteratee ? iteratee(value, i, array) : value;        if (isSorted) {            if (!i || seen !== value) {
                res.push(value)
            }
            seen = value;
        }        else if (iteratee) {            if (seen.indexOf(computed) === -1) {
                seen.push(computed);
                res.push(value);
            }
        }        else if (res.indexOf(value) === -1) {
            res.push(value);
        }        
    }    return res;
}console.log(unique(array3, false, function(item){    return typeof item == &#39;string&#39; ? item.toLowerCase() : item
})); // [1, "a", 2]
登入後複製

在這一版也是最後一版的實作中,函數傳遞三個參數:

array:表示要去重的數組,必填

isSorted:表示函數傳入的陣列是否已排過序,如果為true,將會採用更快的方法進行去重

iteratee:傳入一個函數,可以對每個元素進行重新的計算,然後根據處理的結果進行去重

至此,我們已經仿照著underscore 的思路寫了一個unique 函數,具體可以查看 Github。

filter

ES5 提供了filter 方法,我們可以用來簡化外層循環:

例如使用indexOf 的方法:

var array = [1, 2, 1, 1, &#39;1&#39;];function unique(array) {    var res = array.filter(function(item, index, array){        return array.indexOf(item) === index;
    })    return res;
}console.log(unique(array));
登入後複製

排序去重的方法:

var array = [1, 2, 1, 1, &#39;1&#39;];function unique(array) {    return array.concat().sort().filter(function(item, index, array){        return !index || item !== array[index - 1]
    })
}console.log(unique(array));
登入後複製

Object 鍵值對

去重的方法眾多,儘管我們已經跟著underscore 寫了一個unqiue API,但是讓我們看看其他的方法拓展下視野:

這種方法是利用一個空的Object 對象,我們把數組的值存成Object 的key 值,比如Object[value1] = true,在判斷另一個值的時候,如果Object[value2]存在的話,就說明該值是重複的。範例程式碼如下:

var array = [1, 2, 1, 1, &#39;1&#39;];function unique(array) {    var obj = {};    return array.filter(function(item, index, array){        return obj.hasOwnProperty(item) ? false : (obj[item] = true)
    })
}console.log(unique(array)); // [1, 2]
登入後複製

我們可以發現,是有問題的,因為1 和'1' 是不同的,但是這種方法會判斷為同一個值,這是因為物件的鍵值只能是字串,所以我們可以使用 typeof item + item 拼成字串作為key 值來避免這個問題:

var array = [1, 2, 1, 1, &#39;1&#39;];function unique(array) {    var obj = {};    return array.filter(function(item, index, array)
{        return obj.hasOwnProperty(typeof item + item) ? false : (obj[typeof item + item] = true)
    })
}console.log(unique(array)); // [1, 2, "1"]
登入後複製

ES6

隨著ES6 的到來,去重的方法又有了進展,例如我們可以使用Set 和Map 資料結構,以Set 為例,ES6 提供了新的資料結構Set。它類似於數組,但是成員的值都是唯一的,沒有重複的值。

是不是感覺就像是為去重而準備的?讓我們來寫一版:

var array = [1, 2, 1, 1, &#39;1&#39;];function unique(array) {   return Array.from(new Set(array));
}console.log(unique(array)); // [1, 2, "1"]
登入後複製

甚至可以再簡化下:

function unique(array) {    return [...new Set(array)];
}
登入後複製

還可以再簡化下:

var unique = (a) => [...new Set(a)]
登入後複製

此外,如果用Map 的話:

function unique (arr) {    const seen = new Map()    return arr.filter((a) => !seen.has(a) && seen.set(a, 1))
}
登入後複製

JavaScript 的進化

我們可以看到,去重方法從原始的14 行程式碼到ES6 的1 行程式碼,其實也說明了JavaScript 這門語言在不停的進步,相信以後的開發也會越來越有效率。

特殊型別比較

去重的方法就到此結束了,然而要去重的元素類型可能是多種多樣,除了例子中簡單的1 和'1' 之外,其實還有null、undefined、NaN、物件等,那麼對於這些元素,之前的這些方法的去重結果又是怎麼樣呢?

在此之前,先讓我們先來看幾個例子:

var str1 = &#39;1&#39;;var str2 = new String(&#39;1&#39;);console.log(str1 == str2);
 // trueconsole.log(str1 === str2); // falseconsole.log(null == null);
  // trueconsole.log(null === null); // trueconsole.log(undefined == undefined);
   // trueconsole.log(undefined === undefined); // trueconsole.log(NaN == NaN);
    // falseconsole.log(NaN === NaN); // falseconsole.log(/a/ == /a/); 
    // falseconsole.log(/a/ === /a/); // falseconsole.log({} == {});
     // falseconsole.log({} === {});
      // false
登入後複製

那麼,對於這樣一個陣列

var array = [1, 1, &#39;1&#39;, &#39;1&#39;, null, null, undefined, undefined, new String(&#39;1&#39;), new String(&#39;1&#39;), /a/, /a/, NaN, NaN];
登入後複製

以上各種方法去重的結果到底是什麼樣的呢?

我特地整理了一個列表,我們專注於下物件和NaN 的去重情況:


方法     結果     說明


#for循環   [1, "1", null, undefined, String, String, /a/, /a/, NaN, NaN]    物件與NaN 不去重   

#

indexOf [1, "1", null, undefined, String, String, /a/, /a/, NaN, NaN] 对象和 NaN 不去重

sort [/a/, /a/, "1", 1, String, 1, String, NaN, NaN, null, undefined] 对象和 NaN 不去重 数字 1 也不去重

filter + indexOf [1, "1", null, undefined, String, String, /a/, /a/] 对象不去重 NaN 会被忽略掉

filter + sort [/a/, /a/, "1", 1, String, 1, String, NaN, NaN, null, undefined] 对象和 NaN 不去重 数字 1 不去重

优化后的键值对方法 [1, "1", null, undefined, String, /a/, NaN] 全部去重

Set [1, "1", null, undefined, String, String, /a/, /a/, NaN] 对象不去重 NaN 去重

想了解为什么会出现以上的结果,看两个 demo 便能明白:

// demo1var arr = [1, 2, NaN];
arr.indexOf(NaN); // -1

indexOf 底层还是使用 === 进行判断,因为 NaN ==== NaN的结果为 false,所以使用 indexOf 查找不到 NaN 元素

// demo2function unique(array) {   return Array.from(new Set(array));
}console.log(unique([NaN, NaN])) // [NaN]
登入後複製

Set 认为尽管 NaN === NaN 为 false,但是这两个元素是重复的。

写在最后

虽然去重的结果有所不同,但更重要的是让我们知道在合适的场景要选择合适的方法。

以上内容就是各种不同的JavaScript数组去重方法,如果大家觉得有用的话赶紧收藏起来吧。

相关推荐:

javascript数组去重/查找/插入/删除的方法

js数组去重方法汇总

JavaScript数组去重方法总结

JS实现数组去重的实例介绍

js实现数组去重的几种方法总结

以上是JavaScript的陣列去重方法的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1657
14
CakePHP 教程
1415
52
Laravel 教程
1309
25
PHP教程
1257
29
C# 教程
1229
24
建議:優秀JS開源人臉偵測辨識項目 建議:優秀JS開源人臉偵測辨識項目 Apr 03, 2024 am 11:55 AM

人臉偵測辨識技術已經是一個比較成熟且應用廣泛的技術。而目前最廣泛的網路應用語言非JS莫屬,在Web前端實現人臉偵測辨識相比後端的人臉辨識有優勢也有弱勢。優點包括減少網路互動、即時識別,大大縮短了使用者等待時間,提高了使用者體驗;弱勢是:受到模型大小限制,其中準確率也有限。如何在web端使用js實現人臉偵測呢?為了實現Web端人臉識別,需要熟悉相關的程式語言和技術,如JavaScript、HTML、CSS、WebRTC等。同時也需要掌握相關的電腦視覺和人工智慧技術。值得注意的是,由於Web端的計

如何使用 foreach 迴圈移除 PHP 陣列中的重複元素? 如何使用 foreach 迴圈移除 PHP 陣列中的重複元素? Apr 27, 2024 am 11:33 AM

使用foreach循環移除PHP數組中重複元素的方法如下:遍歷數組,若元素已存在且當前位置不是第一個出現的位置,則刪除它。舉例而言,若資料庫查詢結果有重複記錄,可使用此方法移除,得到不含重複記錄的結果。

PHP數組深度複製的藝術:使用不同方法完美複製 PHP數組深度複製的藝術:使用不同方法完美複製 May 01, 2024 pm 12:30 PM

PHP中深度複製數組的方法包括:使用json_decode和json_encode進行JSON編碼和解碼。使用array_map和clone進行深度複製鍵和值的副本。使用serialize和unserialize進行序列化和反序列化。

PHP 陣列鍵值翻轉:不同方法的效能比較分析 PHP 陣列鍵值翻轉:不同方法的效能比較分析 May 03, 2024 pm 09:03 PM

PHP數組鍵值翻轉方法效能比較顯示:array_flip()函數在大型數組(超過100萬個元素)下比for迴圈效能更優,耗時更短。手動翻轉鍵值的for迴圈方法耗時相對較長。

PHP數組多維排序實戰:從簡單到複雜場景 PHP數組多維排序實戰:從簡單到複雜場景 Apr 29, 2024 pm 09:12 PM

多維數組排序可分為單列排序和嵌套排序。單列排序可使用array_multisort()函數依列排序;巢狀排序需要遞歸函數遍歷陣列並排序。實戰案例包括按產品名稱排序和按銷售量和價格複合排序。

PHP 數組分組函數在資料整理的應用 PHP 數組分組函數在資料整理的應用 May 04, 2024 pm 01:03 PM

PHP的array_group_by函數可依鍵或閉包函數將陣列中的元素分組,傳回關聯數組,其中鍵為組名,值是屬於該組的元素數組。

深度複製PHP數組的最佳實踐:探索高效的方法 深度複製PHP數組的最佳實踐:探索高效的方法 Apr 30, 2024 pm 03:42 PM

在PHP中執行陣列深度複製的最佳實踐是:使用json_decode(json_encode($arr))將陣列轉換為JSON字串,然後再轉換回陣列。使用unserialize(serialize($arr))將陣列序列化為字串,然後將其反序列化為新陣列。使用RecursiveIteratorIterator迭代器對多維數組進行遞歸遍歷。

PHP 陣列分組函數在尋找重複元素中的作用 PHP 陣列分組函數在尋找重複元素中的作用 May 05, 2024 am 09:21 AM

PHP的array_group()函數可用來按指定鍵對陣列進行分組,以尋找重複元素。函數透過以下步驟運作:使用key_callback指定分組鍵。可選地使用value_callback確定分組值。對分組元素進行計數並識別重複項。因此,array_group()函數對於尋找和處理重複元素非常有用。

See all articles