Set與Map集合

by vivid 14. 十二月 2016 12:11

.NET Magazine國際中文電子雜誌
作 者:許薰尹
審 稿:張智凱
文章編號: N161217801
出刊日期: 2016/12/14

本文介紹ECMAScript 2015新增的兩個物件:Set與Map集合。ECMAScript新增Set與Map型別來補足集合的不足,在過去,ECMAScript 5只有一種集合:Array。Array只能夠使用數值當做索引,來存取其中的項目,欠缺使用其它型別的key值做索引的能力。Map集合支援其它型別的key值,而Set型別是一個不重複項目組成的集合,提供快速存取包含在內部項目的特性。

Set集合

要使用Set集合,只需要利用new關鍵字來建立Set集合,然後叫用Set物件的add方法新增項目到其中,參考以下範例程式碼,叫用add方法四次,第一和最後一次呼叫時,新增相同的數值「10」到Set物件之中,而從Size屬性,得到的項目個數是三個,最後使用for..of迴圈印出Set集合中包含的項目只有「10」、「20」、「30」三個,由此可得知,Set只保留不重複的值:

let set = new Set();   
set.add( 10 );
set.add( 20 );
set.add( 30 );
set.add( 10 );
console.log( set.size ); // 3
 
for ( let item of set ) {
   console.log( item ); // 10 20 30
}

 

add方法可以使用串接方式呼叫,一次新增多個項目到集合之中,參考以下範例程式碼,重複叫用add方法新增三個項目到Set之中:

let set = new Set();
set.add( 10 ).add( 20 ).add( 30 );

console.log( set.size ); // 3

for ( let item of set ) {
  console.log( item ); // 10 20 30
}

 

而以下範例新增數值「10」和字串「"10"」到Set之中,Set會視這兩個項目為不同項目,不會自動轉換成相同型別,參考以下範例程式碼,得到的size是2個:

let set = new Set();
set.add( 10 );
set.add( "10" );

console.log( set.size ); // 2

for ( let item of set ) {
  console.log( item ); // 10 10
}


 

使用陣列初始化Set集合

Set的建構函式可以傳入一個列舉子(iterator)或是陣列,將其中的項目存放到Set物件來初始化,參考以下範例程式碼,在建構函式中傳入一個包含三個項目的陣列,這三個項目會自動新增到Set之中:

 

let set = new Set( [10, 20, 30] );
console.log( set.size );    // 3

for ( let item of set ) {
  console.log( item ); //10 20 30
}


 

若陣列中的項目重複,同樣只保留唯一不重複的值,參考以下範例程式碼,陣列中包含重複的項目「30」,而範例使用for .. of迴圈印出Set中的項目得到的結果,「30」只出現一次:

let set = new Set( [10, 20, 30, 30] );
console.log( set.size );    // 3

for ( let item of set ) {
  console.log( item ); // 10 20 30
}


 

判斷項目是否存在Set集合

若要判斷項目是否存在於Set集合之中,可以使用has()方法,它將回傳一個布林值。參考以下範例程式碼,由於Set集合之中包含項目「10」,因此has()方法執行結果將回傳「true」:

let set = new Set( [10, 20, 30] );
console.log( set.has(10) ); // true

 

移除Set集合指定的項目

要移除Set集合指定的項目,可以叫用delete()方法,參考以下範例程式碼,先利用has()方法判斷Set集合中是否存在項目「20」,若是,則將之從Set集合中移除,使用for .. of迴圈印出Set中的項目得到的結果,已不包含「20」:

let set = new Set( [10, 20, 30] );

if ( set.has(20) ) {
  set.delete( 20 ) ;
}

for ( let item of set ) {
  console.log( item ); // 10  30
}

 

清除Set集合項目

若要清除Set集合中所有的項目,可以使用clear()方法,參考以下範例程式碼 ,叫用clear()方法之前,使用size屬性印出Set集合中包含三個項目,叫用clear()之方法後,Size屬性的值就變為0:

let set = new Set( [10, 20, 30] );
console.log( set.size ) // 3
set.clear();
console.log( set.siz e) // 0

 

 

使用forEach方法讀取項目

除了使用先前示範的for..of迴圈取出Set中的項目之外,也可以使用Set集合的forEach()方法,它需要傳入一個回呼函式(callback方法)當參數,你不需要額外再寫一個迴圈,集合中的每一個項目會一一地傳入這個callback方法處理。Map和Array物件都支援forEach()方法,forEach()方法的callback方法可以傳入三個引數,第一個引數代表value;第二個引數代表key;第三個引數則是set物件。因為Set物件並沒有key,因此第一個引數和第二個引數實際上都包含value,這樣callback方法的定義才會和Map、Array物件的一致。參考以下使用forEach()方法的範例程式碼:

let set = new Set();
set.add( 10 ).add( 20 ).add( 30 );

set.forEach(function ( value, key, set ) {
  console.log( key );
  console.log( value );
});

 

 

印出的結果key與value相等:

10
10
20
20
30
30

Callback方法可以改用Arrow Function語法,改寫上述範例如下,程式將變得更簡短,並會得到相同的執行結果:

let set = new Set();
set.add( 10 ).add( 20 ).add( 30 );
set.forEach(( value, key, set ) => {
console.log( key );
console.log( value );
});

 

Set集合轉型成陣列

Set集合無法使用索引來讀取其中的值,若將之轉型成陣列,就可以搭配索引來存取其中的值,參考以下範例程式碼,使用spread operator (展開運算子)將Set中的唯一項目複製到新陣列ar,如此便可以利用陣列來讀取其中的值:

let set = new Set();
set.add( 10 ).add( 20 ).add( 30 ).add( 10 );

let ar = [...set];

for ( var i = 0; i < ar.length; i++ ) {
  console.log( ar[i] ); //10 20 30
}

這個做法非常實用,如果你已經有一個陣列,你想要挑出其中的唯一值放到新陣列,就可以利用Set物件搭配spread operator (展開運算子)。

Map集合

Map是由鍵值/值配對(Key-Value Pairs)項目所成的型別,key和value可以是任意型別,例如物件型別,根據key值,可以取得對應的value。通常Map集合都使用在快取,可以暫存應用程式所需的資料,又能快速存取其中的項目。

參考以下範例程式碼,叫用Map集合的set()方法分別傳入key與value。後續叫用Map集合的get()方法傳入key,就可以取得對應的value:

let map = new Map();
map.set( "id", 1 );
map.set( "name", "mary" );
console.log( map.get( "id" ) ); // 1
console.log( map.get( "name" ) ); // "mary"

key可以是不同型別,因此「1」與「"1"」視為不相同,參考以下範例程式碼,key值分別是字串與數值型別:

let map = new Map();
map.set( "1", "001" );
map.set( 1, 100 );
console.log( map.size ); //2
console.log( map.get("1") ); // "001"
console.log( map.get(1) ); // 100

Set()方法可以使用串接方式進行呼叫,參考以下範例程式碼,連續叫用set()方法新增兩個項目到集合之中:

let map = new Map();
map.set( "id", 1 )
.set( "name", "mary" );
console.log( map.get("id") ); // 1
console.log( map.get("name") ); // "mary"

key可以是任意型別

由於key可以是任意型別,以下範例程式分別利用字串、布林值、數值、物件與Function來當做key值,Map物件的keys()方法可以取得Map物件所有的key,而vlaues方法則可以取的Map物件中所有的value:

let map = new Map([
    [ 'name', 'mary' ],
    [ true, 'false' ],
    [ 1, 'one' ],
    [ {}, 'object' ],
    [ function () { }, 'function' ]
]);

for ( let key of map.keys() ) {
  console.log( typeof key ); // string boolean number object function
};

for ( let value of map.values() ) {
  console.log( value ); //mary false  one object function
};

 

使用陣列初始化Map集合

Map集合的資料可以來自於陣列,只要將陣列傳入Map建構函式之中,陣列中的每一個元素也要宣告為[key,value] (鍵值/值配對,key-value pairs,第一個元素為key值,第二個元素為value),參考以下範例程式碼,新增兩個項物到Map集合之中:

let map = new Map( [ ["id", 1], ["name", "mary"] ] );

for ( let [key, value] of map ) {
console.log( key + " , " + value );
}


使用for of迴圈印出Map中的內容如下:

id , 1
name , mary

 

判斷項目是否存在Map集合

我們可以叫用Map集合has()方法,傳入key值來判斷此項目是否存在於Map集合之中,參考以下範例程式碼 :

let map = new Map();
map.set( "id", 1 );
map.set( "name", "mary" );

console.log( map.has("id") );      // true
console.log( map.has("name") );       // true
console.log( map.has("age") );       // false

for (let [key, value] of map ) {
  console.log( key +" , " + value );
}


使用for of迴圈印出的值如下:

id , 1
name , mary

 

移除Map集合指定項目

要從Map集合中移除指定項目可以使用delete()方法,參考以下範例程式碼,先利用has()方法判斷是否有名為「id」的key值,若存在則刪除:

let map = new Map();
map.set( "id", 1 );
map.set( "name", "mary" );

if ( map.has("id") ) {
  map.delete("id");
}

for ( let [key, value] of map ) {
  console.log( key + " , " + value );
}

 

最後使用for of迴圈印出Map中的項目,只剩下一個name項目:

Name , mary

 

清除Map集合項目

若要清除Map集合中所有的key與value,可以使用clear()方法,參考以下範例程式碼,叫用clear()方法之前,使用size屬性印出Map集合中包含兩個項目,叫用clear()方法之後,Size屬性就變為0:

let map = new Map();
map.set( "id", 1 );
map.set( "name", "mary" );
console.log( map.size ); //2
map.clear();
console.log( map.size ); //0

使用forEach方法

除了使用先前示範的for..of迴圈取出Map集合中的項目之外,也可以使用forEach方法,它需傳入一個callback方法當參數,callback方法中第一個引數代表value;第二個引數代表key;第三個引數則是map物件:

let map = new Map( [ ["id", 1], ["name", "mary"] ] );

map.forEach( function ( value, key, map ) {
  console.log( key + " , " + value );
} );

這個範例印出的結果如下:

id , 1
name , mary

上例的Callback方法可以改用Arrow Function語法,讓程式更為簡潔:

let map = new Map( [ ["id", 1], ["name", "mary"] ] );

map.forEach(( value, key, map ) => {
  console.log( key + " , " + value );
});

 

取得key與value

Map物件包含一個keys()方法,可以取得集合中所有的key;values()方法則可取得集合中所有的值,參考以下範例程式碼,分別利用for of迴圈取得Map物件中所有的key與value:

let map = new Map( [ ["id", 1], ["name", "mary"] ] );

for ( const k of map.keys() ) {
  console.log( k ); // id name
}

for ( const v of map.values() ) {
  console.log( v ); // 1 mary
}

 

取得Map集合中的項目

若要取得Map集合中的項目,可以叫用entries()方法,它會將集合中的每個項目放到一個陣列之中,陣列索引0的位置包含key;陣列索引1的位置包含value,參考以下範例程式碼:

let map = new Map( [ ["id", 1] , ["name", "mary"] ] );

for ( const e of map.entries() ) {
  console.log( e[0], e[1] );
}


 

此範例的執行結果如下:

id 1
name mary

 

Map集合轉換成陣列

若要將Map集合轉換成陣列,可以使用spead operator(展開運算子,…),參考以下範例程式碼,分別將Map中的項目、Map中所有項目的key與Map中所有項目的values轉換成陣列,並印出陣列中的內容:

let map = new Map( [ ["id", 1], ["name", "mary"] ] );

let ar = [...map];

for ( const item of map ) {
  console.log( item[0] +" , " + item[1] ); // id , 1 name , mary
}

let arKeys = [...map.keys()];

for ( const item of arKeys ) {
  console.log( item ); // id name
}

let arValues = [...map.values()];

for ( const item of arValues ) {
  console.log( item ); // 1 mary
}

 

合併Map集合

若要合併兩個以上的Map物件,只需要將要合併的Map集合先利用spead operator(展開運算子,…)轉換成陣列,將產生的陣列傳入Map建構函式進行初始化,參考以下範例程式碼:

let map1 = new Map( [ ["id", 1], ["name", "mary"] ] );
let map2 = new Map( [ ["age", 20], ["phone", "123456"] ] );

let map = new Map( [...map1,...map2] );

for ( const [key , value] of map ) {
  console.log( key +  " , "  + value );
}

 

此範例的執行結果如下:

id , 1
name , mary
age , 20
phone , 123456

Tags:

.NET Magazine國際中文電子雜誌 | JavaScript | 許薰尹Vivid Hsu

新增評論




  Country flag
biuquote
  • 評論
  • 線上預覽
Loading






NET Magazine國際中文電子雜誌

NET Magazine國際中文電子版雜誌,由恆逸資訊創立於2000,自發刊日起迄今已發行超過500篇.NET相關技術文章,擁有超過40000名註冊讀者群。NET Magazine國際中文電子版雜誌希望藉於電子雜誌與NET Developer達到共同學習與技術新知分享,歡迎每一位對.NET 技術有興趣的朋友們多多支持本雜誌,讓作者群們可以有持續性的動力繼續爬文。<請加入免費訂閱>

月分類Month List