【譯】Array與Set的異同及使用場景

Set vs Array
原文連接: 戳這裏
PS:原文只介紹了Array和Set的一些簡單操做,詳細API放在文章底部。

Array和Set是什麼

每個使用JavaScript編程的人都應該對Array很是熟悉。 一般,咱們能夠這樣形容它:數組是表示一種儲存在連續空間中的結構類型(內容能夠爲number,object等)。 例如:[1, 2, 3, 4, 5]
(原文這裏說法存在歧義,具體數組在內存中的存儲方式能夠參考連接一連接二javascript

而Set更像是一種抽象的數據類型。它只包含不一樣的元素/對象,不須要連續分配存儲空間。 例如:{1, 2, 3}java

它們之間最大的差異就是Array中的元素是能夠重複的,而Set中的元素不可重複 。除此以外,Array被認爲是一種索引集合,而Set是一種鍵的集合。es6

索引集合是指按下標做爲索引值排序的數據結構
鍵的集合使用key訪問元素,訪問順序與元素插入順序一致。編程

很簡單對吧?如今可能有人會問,既然這二者如此不一樣,爲何還要將它們進行比較?數組

在編程時,咱們可使用Array或Set來存儲相同的數據集。但根據使用狀況,咱們應該選用正確的數據結構以助於提供最佳的解決方案。爲了實現這個目標,首先咱們須要瞭解它們分別是什麼,有什麼特色和能力。前面的文章中咱們對這兩種數據結構已經有了初步的瞭解,接下來就來看看它們的構建方式。瀏覽器

如何構建

Array

數組的構建很是簡單直接,在JS中聲明一個數組你能夠直接使用字面上的語法:數據結構

var arr = []; //空數組
var arr = [1,2,3]; //元素爲1,2,3的數組
複製代碼

或者使用構造函數:函數

var arr = new Array(); //空數組
var arr = new Array(1,2,3);//元素爲1,2,3的數組
複製代碼

甚至這種更酷的方法:性能

var arr = Array.from("123"); //["1","2","3"]
複製代碼

注: 一條建議——除了非用不可的狀況儘可能不要使用new Array(),緣由以下:ui

  • new Array()的性能比[]慢不少
  • []節約更多輸入的時間
  • 你可能會犯一些經典的錯誤,好比:
var arr1 = new Array(10); //長度爲10,每一個元素都爲undefined
var arr2 = [10]; // arr2[0] = 10 且 arr2.length = 1;
var arr3 = new Array(1,2,3); //[1,2,3]
var arr4 = [1,2,3];//[1,2,3] 
複製代碼

因此,儘可能保持一個原則——簡單化

Set

Set使用內置的構造函數初始化,沒有其它簡便的方法。

Set([iterable])

想要建立一個Set,須要使用new方法,例如:

var emptySet = new Set(); 
var exampleSet = new Set([1,2,3]);
複製代碼

不能使用以下方式:

new Set(1);
複製代碼

Set接收一個可遍歷的對象做爲其輸入參數,並將遍歷元素依次做爲Set中的元素生成對象。所以,咱們能夠經過數組做爲參數去建立Set——但建立的Set中只包含數組中的非重複元素,如上文提到,Set中元素不可重複。

固然,咱們也能經過Array.from()方法將Set還原爲數組:

var set = new Set([1,2,3]); // {1,2,3}
var arr = Array.from(set);//[1,2,3]
複製代碼

如今,咱們知道了如何構建這兩種數據結構,接下來讓咱們對Array / Set提供的最基本方法進行比較。

訪問元素

  • 首先Set不支持像Array同樣經過索引隨機訪問元素
console.log(set[0]); //undefined
console.log(arr[0]); //1
複製代碼
  • 更重要的是,由於Array中的數據存儲在連續的空間中,因此CPU可以經過預處理操做更快地進行數據訪問。所以,與其餘類型的抽象數據類型進行比較,訪問Array中的元素(按順序,例如for循環)一般會更快更有效。
  • 判斷一個元素是否在Set中的語法比判斷是否在Array中更簡潔。Set:Set.prototype.has(value)。Array:Array.prototype.indexOf(value)
console.log(set.has(0)); // boolean - false
console.log(arr.indexOf(0)); // -1
console.log(set.has(1)); //true
console.log(arr.indexOf(1)); //0
複製代碼

這意味着在Array中,咱們須要額外建立檢查元素是否在Array中的條件:

var isExist = arr.indexOf(1) !== -1;
複製代碼

:ES6提供了與Set.prototype.has()類似的方法Array.prototype.includes()來判斷元素是否在數組中,但這個方法並無普遍地被瀏覽器支持——好比IE..

插入元素

Array

  • 向數組中插入元素可使用時間複雜度爲O(1)的Array.prototype.push()方法快速完成——元素將會被插入到數組的末尾。
arr.push(4); //[1,2,3,4]
複製代碼
  • 或者可使用時間複雜度爲O(n)的Array.prototype.unshift()方法實現——元素被插入到數組的頭部。
arr.unshift(3); //[3,1,2,3]
arr.unshift(5, 6); //[5,6,3,1,2,3]
複製代碼

Set

  • 只有一個方法能夠在Set中插入元素——Set.prototype.add()。因爲Set須要保持其「元素不可重複」的特性,因此每次調用add()方法,Set都須要便利全部元素以確保無重複元素,一般狀況下add()方法的時間複雜度應爲O(n)。不過Set的內部採用哈希表的實現方式,所以能夠達到O(1)的時間複雜度。
set.add(3); //{1,2,3} 
set.add(4); //{1,2,3,4}
複製代碼

刪除元素

Array

  • 使數組如此受歡迎的緣由之一是它提供了許多不一樣的方法去刪除元素,例如:
var arr = [5, 6, 1, 2, 3, 4]
複製代碼

pop()——刪除並返回最後一個元素,時間複雜度O(1)

arr.pop();//return 4, [5,6,1,2,3]
複製代碼

shift()——刪除並返回第一個元素,時間複雜度O(n)

arr.shift(); //return 5; [6,1,2,3]
複製代碼

splice(index, delectCount)——刪除從index開始的delectCount個元素。時間複雜度爲O(n)

arr.splice(0,1); //[1,2,3]
複製代碼

Set

var set = new Set([1, 2, 3, 4]);
複製代碼

delete(element)——刪除指定的element

set.delete(4); //{1,2,3}
複製代碼

clear()——清空Set中全部元素

set.clear(); //{}
複製代碼

Array並未提供原生方法刪除指定元素,咱們須要藉助其它方法找到元素對應下標,經過splice()刪除,而Set能夠直接使用delete()進行刪除。

另外,對比Set只提供了一些基本的操做數據的方法,Array提供了更多實用的原生方法(reduce(),map(),sort()等),因此有些人可能會想,爲何咱們比起Array會更喜歡Set?

Array和Set的應用場景

  • 首先,Set與Array是不一樣的兩種數據結構,它並非要徹底替換Array,而是提供額外的數據類型來完成Array缺乏的一些功能。
  • 因爲Set只包含不一樣的元素,若是咱們只但願存儲不一樣的元素,使用Set會更好。
  • 能夠利用Set的一些原生方法輕鬆的完成數組去重,查找數組公共元素及不一樣元素等操做。Set的delete()方法,使求兩個Set的交/並集的操做比求兩個數組的交/並集的操做更簡單。
  • 數組適用於但願保留重複元素,可能進行大量修改(增、刪操做),或是但願經過索引對元素進行快速訪問的場景。(試想對一個Set進行二分查找——如何獲取到Set的中間元素?)

結論

總之,就我而言對比Array,Set並無明顯優點,除了在特定場景中,例如當咱們想要以最小成本維護不重複的數據,或者使用到大量不一樣的數據集時只須要使用最基本的集合操做而無需直接訪問元素。

不然,Array一般是更好的選擇。由於在須要時獲取元素更節省CPU工做量。

歡迎討論。

其餘資料連接:

相關文章
相關標籤/搜索