【JavaScript】連想配列(Map)の使い方まとめ

JavaScriptで連想配列(辞書)というと、Object型とMap型の二つがあります。

今回は、動的に要素を追加削除するのに適したMap型について、使い方をまとめていきます。

Mapの作成

Mapはnew Map()で作成します。

標準組み込みオブジェクトなので特別なimport等は不要です。

let myMap= new Map();

Map作成時に要素を設定することも可能です。

let myMap = new Map([
  ['key1', 'val1'],
  ['key2', 'val2']
]);

console.log(myMap); // Map(2) {"key1" => "val1", "key2" => "val2"}

要素の追加

要素の追加はset()を使用します。

重複するキーがあった場合は後勝ち(上書き)の動作になります

let myMap= new Map();

// 要素の追加
myMap.set('key1', 'val1');
myMap.set('key2', 'val2');

console.log(myMap); // Map(2) {"key1" => "val1", "key2" => "val2"}

// キーが重複する要素を追加
myMap.set('key1', 'UPDATED');

// 後勝ちの動作になる
console.log(myMap); // Map(2) {"key1" => "UPDATED", "key2" => "val2"}

要素の取得

要素の取得はget()を使用します。

let myMap = new Map([['key1', 'val1'], ['key2', 'val2']]);

let x = myMap.get('key1');

console.log(x); // val1

一覧の取得

キーの一覧

配列を作成するArray.from()keys()を指定することでキーの一覧の配列を作成することができます。

let myMap = new Map([['key1', 'val1'], ['key2', 'val2']]);

let keyArray = Array.from(myMap.keys());
console.log(keyArray); // ["key1", "key2"]

要素(バリュー)の一覧

配列を作成するArray.from()values()を指定することでバリューの一覧の配列を作成することができます。

let myMap = new Map([['key1', 'val1'], ['key2', 'val2']]);

let valueArray = Array.from(myMap.values());
console.log(valueArray); // ["val1", "val2"]

また、entries()を指定することでキーバリューの一覧を作成することも可能です。

要素の判定(存在チェック)

has()を使用して要素の存在をチェックすることができます。

存在しない要素に対してget()を使用すると”undefined”が返るため、get()で代用も可能です。

ただ、”undefined”判定の書き方で悩むぐらいならhas()を使う方が健全だとは思います。

let myMap = new Map([['key1', 'val1'], ['key2', 'val2']]);

// 要素の存在チェック
if (myMap.has('key2')) {
    console.log('DEFINED');
}

// undefined判定で代用可能
if (typeof myMap.get('key3') === 'undefined') {
    console.log('UNDEFINED')
}

要素数 (長さ)の取得

要素数の取得はsize属性で取得します。

let myMap = new Map([['key1', 'val1'], ['key2', 'val2']]);

// 要素数の取得
let size = myMap.size;

console.log(`size=${size}`); // size=2

Object型よりもコードがすっきりするので良いですね。

// Object型の場合
let myDict = { key1: 'hoge', key2: 'fuga', key3: 'piyo'}
let len = Object.keys(myDict).length

要素の削除

要素の削除はdelete()を使用します。
返り値はtrue(削除成功)/false(削除失敗)です。

let myMap = new Map([['key1', 'val1'], ['key2', 'val2']]);

// 要素の削除
let returnValue = myMap.delete('key2');

console.log(returnValue); // true


// 削除に失敗した(キーが存在しない)場合はfalseが返る
returnValue = myMap.delete('key2');

console.log(returnValue); // false

ループ・繰り返し処理

ループ処理の書き方は何通りもあるかと思いますが、ここではよく使いそうな4パターンをご紹介します。

①・②:キー/バリューをループさせたい場合
③:キーのみループさせたい場合
④:バリューのみループさせたい場合

// ループ処理①:よくあるfor文の書き方
for (const [key, value] of myMap.entries()) {
    console.log(`key=${key}, value=${value}`);
}

// ループ処理②:forEachを使った書き方 ★オススメ★
// パラメータ順が(value, key)なので注意
myMap.forEach((value, key) => {
    console.log(`key=${key}, value=${value}`);
});

// ループ処理③:キーだけ回したい場合
for (const key of myMap.keys()) {
    console.log(`key=${key}`);
}

// ループ処理④:バリューだけ回したい場合
for (const value of myMap.values()) {
    console.log(`value=${value}`);
}

①と②は実現できることは同じですが、②の方が1.5倍ほど性能が良かったです。
(測定結果はこちら)

コーディング規約や趣味嗜好のしがらみがなければ②の書き方がおすすめです。

連想配列の結合(マージ)

連想配列を結合する場合は、結合元のMapを展開して新しいMapとして定義することで結合することができます。

要素追加と同じく、重複するキーは後勝ちの論理が働きます。

let myMap1 = new Map([['key1', 'val1'], ['key2', 'val2']]);
let myMap2 = new Map([['key1', 'new val1']]);
let myMap3 = new Map([['key3', 'val3'],['key4', 'val4']]);

// 連想配列の結合
let mergedMap1 = new Map([...myMap1, ...myMap2]); //...はスプレッド演算子で、要素の展開を行う

// 後勝ちなので、key1はmyMap2の値が残る
console.log(mergedMap1); // Map(2) {"key1" => "new val1", "key2" => "val2"}


// 3つ以上の連想配列の結合も可
let mergedMap2 = new Map([...myMap1, ...myMap2, ...myMap3]);

console.log(mergedMap2); // Map(4) {"key1" => "new val1", "key2" => "val2", "key3" => "val3", "key4" => "val4"}


// [key, value]の記法と組み合わせることも可
let mergedMap3 = new Map([...myMap1, ...myMap2, ['key5', 'val5'], ['key6', 'val6']]);

console.log(mergedMap3); // Map(4) {"key1" => "new val1", "key2" => "val2", "key5" => "val5", "key6" => "val6"}

参考

Mapについて
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Map

スプレッド構文について
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Spread_syntax

undefined値の判定について
http://blog.tojiru.net/article/205007468.html

コメント

タイトルとURLをコピーしました