JavaScriptのMapの使い方と具体例
JavaScriptのMapはとても便利なので詳しくみていきましょう。
Mapの使い方
Mapオブジェクトはキーと値のペアを保持します。
そして、キーが最初に挿入された順序を覚えてくれているので、それを利用することができます。
キーや値には任意の値 (オブジェクトとプリミティブ値)を使用することができるため、Mapはどんなデータ型でも使うことができます。
まずはmapに情報をセットする方法をみていきましょう。
Mapとset
{
const rest = new Map();
rest.set('name', '居酒屋エンジニア');
rest.set('1', '東京、日本');
console.log(rest); //Map(2) {"name" => "居酒屋エンジニア", "1" => "東京、日本"}
}
このようにMapは次々とsetで設定された値を格納していくことができます。
setとチェーンして使用
setはチェーンして設定していくことができます。
{
const rest = new Map();
rest.set('categories', ['中華', '和食','イタリアン', 'フレンチ', 'アフリカン']).set('open', 10).set('close', 22).set(true, '営業中です:)').set(false, '閉店中ですm(_ _)m');
}
Mapとget
{
//getで取得
const rest = new Map();
rest.set('categories', ['中華', '和食','イタリアン', 'フレンチ', 'アフリカン']).set('open', 10).set('close', 22).set(true, '営業中です:)').set(false, '閉店中ですm(_ _)m');
console.log(rest.get('name')); //居酒屋エンジニア
console.log(rest.get(true)); //営業中です:)
console.log(rest.get('categories')); //(5) ["中華", "和食", "イタリアン", "フレンチ", "アフリカン"]
}
Mapとtrue/falseを上手に使う
{
//true/falseを上手に使う
const rest = new Map();
rest.set('categories', ['中華', '和食','イタリアン', 'フレンチ', 'アフリカン']).set('open', 10).set('close', 22).set(true, '営業中です:)').set(false, '閉店中ですm(_ _)m');
const time = 20;
const openMsg = rest.get(time > rest.get('open') && time < rest.get('close'));
console.log(openMsg); //trueが返されて「営業中です:)」が表示される
}
Mapとhas
{
//has
const rest = new Map();
rest.set('categories', ['中華', '和食','イタリアン', 'フレンチ', 'アフリカン']).set('open', 10).set('close', 22).set(true, '営業中です:)').set(false, '閉店中ですm(_ _)m');
console.log(rest.has('categories')); //true
}
Mapとdelete
{
//delete
rest.delete(1);
}
Mapとsize
{
//size
const rest = new Map();
rest.set('categories', ['中華', '和食','イタリアン', 'フレンチ', 'アフリカン']).set('open', 10).set('close', 22).set(true, '営業中です:)').set(false, '閉店中ですm(_ _)m');
console.log(rest.size);//5
}
sizeはlengthの代わりに使うと便利です。
Mapとclear
{
//clear
rest.clear();
}
配列をキーとして使う
//配列をキーとして使うとき
const arr = [2,2];
rest.set(arr, 'テスト');
console.log(rest);
console.log(rest.size);
console.log(rest.get(arr));
配列をキーとして呼び出すときは、console.log(rest.get([2,2]))として呼び出すこととはできません。
それはメモリーと参照のところで説明しています。
そのため、配列をキーとするのであれば、一度変数に入れてから使う必要があります。
整理すると、Mapへはsetを使うことで、[2,2]といった配列でもキーとして設定することができますが、呼び出すときには、[2,2]では完全に新しい配列になってしまっているため呼び出せません。
そのため、キーとなる部分を変数で置き換えます。
DOMを操作する
//DOMを操作する
const h1 = new Map();
h1.set(document.querySelector('h1'), 'Heading');
console.log(h1);
実際にコンソールで確認すると、h1にカーソルをあわせることでh1を要素選択できることがわかります。
たくさん値があるときに便利にセットする方法
{
//たくさん値があるときに便利にセットする方法
const question = new Map([
['質問', '世界で最も使われているプログラミング言語はなんでしょうか。'],
[1, 'C'],
[2, 'Java'],
[3, 'JavaScript'],
['正解', 3],
[true, '正解'],
[false, '残念、もう一度'],
]);
console.log(question);
}
setを使ってもいいのですが、このようにすると、見やすくいっきに設定することができます。
オブジェクトをMapに変換する
次のオブジェクトをMapに変換したいとします。
上のMapをコンソールでみると「entries」ということばが見つかります。とてもオブジェクトに似た形をしているのがわかると思います。
オブジェクトにObject.entries()を使うことで簡単にMapに変換することができます。
{
//オブジェクトをMapに変換する
const openingHours = {
wed: {
open: 12,
close: 22,
},
thu: {
open: 11,
close: 23,
},
fri: {
open: 0, // Open 24 hours
close: 24,
},
};
console.log(openingHours);
//const hoursMap = new Map(openingHours); これはできない。objectはiterableじゃないため。
const hoursMap = new Map(Object.entries(openingHours));
console.log(hoursMap);
}
オブジェクトはiterableではないため、forループがつかえません。
しかし、mapはiterableのため、forループが使えます。
そして、オブジェクトからmapへの変換はとても簡単です。
Mapでforループを使う
{
const question = new Map([
['質問', '世界で最も使われているプログラミング言語はなんでしょうか。'],
[1, 'C'],
[2, 'Java'],
[3, 'JavaScript'],
['正解', 3],
[true, '正解'],
[false, '残念、もう一度'],
]);
console.log(question.get('質問'));
世界で最も使われているプログラミング言語はなんでしょうか。
for (const [key, value] of question) {
if(typeof key === 'number') console.log(`答えは ${key}: ${value}`);
答えは 1: C
答えは 2: Java
答えは 3: JavaScript
}
const answer = Number(prompt('あなたの答えは?'));
console.log(answer);
console.log(question.get(question.get('正解') === answer));
}
question.get('正解’) === answerという条件がtrueの場合、すでにMapに [true, '正解’]と返す配列が入っていますので、
3という正解が返ってくれば、question.get(true)という形に変換されます。
それ以外がanswerとして回答されると、question.get(false)となり、falseの文が返されます。
Mapを配列に変換する
[]をつけるだけなのでとても簡単です。
{
const question = new Map([
['質問', '世界で最も使われているプログラミング言語はなんでしょうか。'],
[1, 'C'],
[2, 'Java'],
[3, 'JavaScript'],
['正解', 3],
[true, '正解'],
[false, '残念、もう一度'],
]);
console.log([...question]);
// entries()を使うとキーとバリューを取り出せる
console.log([...question.keys()]);
console.log([...question.values()]);
}
map()で返された関数の値を別の関数を作って返す
配列に何らかの処理をして、その結果を別の配列にしたい場合があります。
そんなときにmap()を使います。
map()は返された関数の値を別の関数を作って返すことができます。
たとえば10円ずつ値下げしたいとします。
すでに200円,300円,400円という値段にそれぞれ10円引いた結果がほしい場合、次のようになります。
'use strict';
{
const prices = [200, 300, 400];
const discountedPrices = prices.map((price) => {
return price - 10;
});
console.log(discountedPrices);
//より短く書く場合、次のようにもかけます。
//const prices = [200, 300, 400];
// const discountedPrices = price.map(price => price - 10);
//console.log(discountedPrices);
}
まずmap()で返される値を格納するため、定数を作ってあげます。
今回は割引するのでdiscountedPricesという定数名にします。
そして、引数としてpriceを用意しておきます。
返す処理を書いてreturnすることで、pricesのそれぞれの値が引数priceに渡されます。
そしてそれぞれ10円値引きした値を返し、discountedPricesに格納すことができます。
mapの挙動まとめ
const gameEvents = new Map([
[15, '⚽️ ゴール'],
[33, '🔁 選手交代'],
[48, '⚽️ ゴール'],
[61, '🔁 選手交代'],
[67, '🔶 イエローカード'],
[69, '🔴 レッドカード'],
[70, '🔁 選手交代'],
[76, '🔁 選手交代'],
[78, '⚽️ ゴール'],
[85, '⚽️ ゴール'],
[90, '🔶 イエローカード'],
]);
/* ========================= */
/* lengthを取得したい */
/* ========================= */
console.log(gameEvents.size);//11
/* ========================= */
/* mapの状態で値とキーを取得したい */
/* ========================= */
//mapの状態でvaluesを取得する
console.log(gameEvents.values());
/*
MapIterator {"⚽️ ゴール", "🔁 選手交代", "⚽️ ゴール", "🔁 選手交代", "🔶 イエローカード", …}
[[Entries]]
0: "⚽️ ゴール"
1: "🔁 選手交代"
2: "⚽️ ゴール"
3: "🔁 選手交代"
4: "🔶 イエローカード"
5: "🔴 レッドカード"
6: "🔁 選手交代"
7: "🔁 選手交代"
8: "⚽️ ゴール"
9: "⚽️ ゴール"
10: "🔶 イエローカード"
*/
//mapの状態でkeysを取得する
console.log(gameEvents.keys());
/*返される値
MapIterator {15, 33, 48, 61, 67, …}
[[Entries]]
0: 15
1: 33
2: 48
3: 61
4: 67
5: 69
6: 70
7: 76
8: 78
9: 85
10: 90
*/
/* ========================= */
/* 一文で取得したい */
/* スプレッド構文 */
/* ========================= */
//スプレッド構文でvaluesだけ取得する
console.log(...gameEvents.values());
//⚽️ ゴール 🔁 選手交代 ⚽️ ゴール 🔁 選手交代 🔶 イエローカード 🔴 レッドカード 🔁 選手交代 🔁 選手交代 ⚽️ ゴール ⚽️ ゴール 🔶 イエローカード
//スプレッド構文でkeysだけ取得する
console.log(...gameEvents.keys());
//15 33 48 61 67 69 70 76 78 85 90
/* ========================= */
/* mapを配列で取得したい */
/* 配列+スプレッド構文 */
/* ========================= */
//配列+スプレッド構文でvaluesだけの配列をつくる
console.log([...gameEvents.values()]);
//(11) ["⚽️ ゴール", "🔁 選手交代", "⚽️ ゴール", "🔁 選手交代", "🔶 イエローカード", "🔴 レッドカード", "🔁 選手交代", "🔁 選手交代", "⚽️ ゴール", "⚽️ ゴール", "🔶 イエローカード"]
//配列+スプレッド構文でkeysだけの配列をつくる
console.log([...gameEvents.keys()]);
//(11) [15, 33, 48, 61, 67, 69, 70, 76, 78, 85, 90]
/* ========================= */
/* mapの重複を削除したい *
/* set+配列+スプレッド構文 */
/* ========================= */
//set+配列+スプレッド構文でvaluesだけのsetをつくる
console.log(new Set([...gameEvents.values()]));
/*
Set(4) {"⚽️ ゴール", "🔁 選手交代", "🔶 イエローカード", "🔴 レッドカード"}
[[Entries]]
0: "⚽️ ゴール"
1: "🔁 選手交代"
2: "🔶 イエローカード"
3: "🔴 レッドカード"
*/
//set+配列+スプレッド構文でkeysだけのsetをつくる
console.log(new Set([...gameEvents.keys()]));
/*
Set(11) {15, 33, 48, 61, 67, …}
[[Entries]]
0: 15
1: 33
2: 48
3: 61
4: 67
5: 69
6: 70
7: 76
8: 78
9: 85
10: 90
*/
/* ========================= */
/* ループとの組み合わせ */
/* ========================= */
for (const [key, value] of gameEvents) {
const half = key <= 45 ? '1st': '2nd';
console.log(`[${half} HALF] ${key}: ${value}`);
}
/*
Set(11) {15, 33, 48, 61, 67, …}
[1st HALF] 15: ⚽️ ゴール
[1st HALF] 33: 🔁 選手交代
[2nd HALF] 48: ⚽️ ゴール
[2nd HALF] 61: 🔁 選手交代
[2nd HALF] 67: 🔶 イエローカード
[2nd HALF] 69: 🔴 レッドカード
[2nd HALF] 70: 🔁 選手交代
[2nd HALF] 76: 🔁 選手交代
[2nd HALF] 78: ⚽️ ゴール
[2nd HALF] 85: ⚽️ ゴール
*/
mapから、重複のない値のみの配列をつくりたい
- mapのvalues()をスプレッド構文を使って配列にする(重複のある値のみの配列がつくれる)
- それをsetにセットして新しい変数に格納する(重複した値が取り除かれる)
- setから配列に変換する
という順番です。
const gameEvents = new Map([
[15, '⚽️ ゴール'],
[33, '🔁 選手交代'],
[48, '⚽️ ゴール'],
[61, '🔁 選手交代'],
[67, '🔶 イエローカード'],
[69, '🔴 レッドカード'],
[70, '🔁 選手交代'],
[76, '🔁 選手交代'],
[78, '⚽️ ゴール'],
[85, '⚽️ ゴール'],
[90, '🔶 イエローカード'],
]);
let eventsSet = new Set([...gameEvents.values()]);
console.log(eventsSet);
//Set(4) {"⚽️ ゴール", "🔁 選手交代", "🔶 イエローカード", "🔴 レッドカード"}
const events = [...new Set(eventsSet)];//setから配列に変換
console.log(events);
/*
["⚽️ ゴール", "🔁 選手交代", "🔶 イエローカード", "🔴 レッドカード"]
0: "⚽️ ゴール"
1: "🔁 選手交代"
2: "🔶 イエローカード"
3: "🔴 レッドカード"
*/
Setに関しては次の記事を参考にしてみてください。