
C++入門|連想配列とmap
番号ではなく名前で探す。mapを使えば、戦士名や技名から必要なデータをすぐに取り出せます。
STLには、vectorやlistのほかにも、データを便利に管理するためのクラスがいくつも用意されています。
その中でも、今回学ぶmapは、名前や文字列などを手がかりにして値を取り出せる、とても実用的なクラスです。
vectorでは、0番目、1番目、2番目のように、番号を使って要素へアクセスしました。
listでは、イテレータを使って、先頭から順番に要素をたどりました。
mapでは、番号ではなくキーを使って値へアクセスします。
たとえば、修行場にいる戦士の修行得点を管理したいとします。
vectorで管理する場合、0番目が誰、1番目が誰、2番目が誰なのかを別に覚えておく必要があります。
しかしmapを使えば、戦士名そのものをキーにできます。
リクという名前を指定すればリクの得点を取り出し、ソラという名前を指定すればソラの得点を取り出せます。
ドラゴンボール風にたとえるなら、mapは神殿の修行記録帳です。
戦士名を調べると、その戦士の修行得点や戦闘力がすぐに分かるような仕組みです。
このように、キーと値を組み合わせて管理する配列のような仕組みを、連想配列といいます。
| 用語 | 意味 | ドラゴンボール風のイメージ |
|---|---|---|
| map | キーと値を組み合わせて管理するSTLのクラス | 修行記録帳 |
| キー | 値を探すための手がかり | 戦士名、技名、流派名 |
| 値 | キーに対応して保存されるデータ | 修行得点、戦闘力、技の威力 |
| 連想配列 | 番号ではなくキーで値を取り出す配列のような仕組み | 名前で探せるデータ帳 |
mapとは何か
mapは、キーと値を1組にして管理するSTLのクラスです。
配列やvectorでは、要素へアクセスするときに番号を使います。
scores[0]
scores[1]
scores[2]一方、mapでは、番号ではなくキーを使います。
trainingScore["リク"]
trainingScore["ソラ"]
trainingScore["レン"]この書き方を見ると、どの戦士の得点を扱っているのかがすぐに分かります。
たとえば、trainingScore["リク"] は、リクというキーに対応する値を表します。
trainingScore["ソラ"] は、ソラというキーに対応する値を表します。
このように、mapでは意味のある名前を使ってデータへアクセスできます。
辞書を思い浮かべると、mapの考え方はとても分かりやすくなります。
辞書では、調べたい単語を探すと、その意味が分かります。
mapでも同じように、キーを指定すると、そのキーに対応する値が分かります。
| 辞書の考え方 | mapの考え方 |
|---|---|
| 単語を調べる | キーを指定する |
| 意味が分かる | 値を取り出す |
| 単語と意味が対応する | キーと値が対応する |
ドラゴンボール風に考えると、戦士名を調べると修行得点が分かる記録帳です。
リクという戦士名を調べれば100点、ソラという戦士名を調べれば80点、レンという戦士名を調べれば76点、というように対応します。
図:連想配列とmapの基本イメージ

この図が示していること
この図では、mapがキーと値を対応付けて管理する仕組みを表しています。
リク、ソラ、レンという戦士名がキーです。
100点、80点、76点という修行得点が値です。
mapでは、番号ではなくキーを使って値を取り出します。
そのため、誰のデータを扱っているのかが分かりやすくなります。
vectorとmapの違い
vectorとmapは、どちらも複数のデータを管理できます。
しかし、データの取り出し方が大きく違います。
vectorは、番号で要素にアクセスします。
vector<int> scores;
scores.push_back(100);
scores.push_back(80);
scores.push_back(76);
cout << scores[0] << endl;この場合、scores[0] は最初の要素を表します。
ただし、0番目が誰の点数なのかは、コードだけでは分かりにくいことがあります。
一方、mapではキーを使います。
map<string, int> trainingScore;
trainingScore["リク"] = 100;
trainingScore["ソラ"] = 80;
trainingScore["レン"] = 76;
cout << trainingScore["リク"] << endl;この場合、trainingScore["リク"] はリクの修行得点を表します。
コードを読んだだけで、どの戦士の点数なのかが分かります。
| 比較項目 | vector | map |
|---|---|---|
| アクセス方法 | 番号でアクセスする | キーでアクセスする |
| 例 | scores[0] | trainingScore["リク"] |
| 向いている場面 | 順番が重要なデータ | 名前と値を対応させたいデータ |
| イメージ | 番号付きの修行ボード | 名前で探せる修行記録帳 |
vectorは、順番に並んだデータを扱うときに便利です。
mapは、名前やIDなどのキーから値を取り出したいときに便利です。
mapを使う準備
mapを使うには、map用のヘッダーをインクルードします。
#include <map>また、今回のサンプルではstring型も使うため、string用のヘッダーもインクルードします。
#include <string>画面に表示するためにiostreamも使います。
#include <iostream>今回のサンプルでは、標準名前空間を使えるようにします。
using namespace std;mapの基本的な宣言は、次の形です。
map<キーの型, 値の型> 変数名;たとえば、戦士名を文字列、修行得点を整数で管理するなら、次のように書きます。
map<string, int> trainingScore;この宣言では、キーの型がstring、値の型がintになります。
つまり、文字列のキーを使って、整数の値を保存するmapを作っています。
| 宣言の部分 | 意味 |
|---|---|
| map | mapクラスを使う |
| string | キーの型 |
| int | 値の型 |
| trainingScore | mapの変数名 |
mapを使ったサンプルプログラム
ここでは、戦士名と修行得点を対応付けるプログラムを作ります。
リク、ソラ、レンという3人の戦士に対して、それぞれ修行得点を登録します。
そのあと、戦士名をキーとして得点を取り出して表示します。
プロジェクト/ファイル名: Chap6_08/training_score_map.cpp
#include <iostream>
#include <string>
#include <map>
using namespace std;
int main(int argc, char** argv) {
// 戦士名と修行得点を対応付けて管理するmap
map<string, int> trainingScore;
// 戦士名をキーにして修行得点を登録する
trainingScore["リク"] = 100;
trainingScore["ソラ"] = 80;
trainingScore["レン"] = 76;
// キーを指定して修行得点を取り出す
cout << "リクの修行得点は" << trainingScore["リク"] << "点です。" << endl;
cout << "ソラの修行得点は" << trainingScore["ソラ"] << "点です。" << endl;
cout << "レンの修行得点は" << trainingScore["レン"] << "点です。" << endl;
// プログラムが正常に終わったことを示す
return 0;
}実行結果
リクの修行得点は100点です。
ソラの修行得点は80点です。
レンの修行得点は76点です。このプログラムでは、trainingScoreというmapを使っています。
map<string, int> trainingScore;この1行で、戦士名と修行得点を対応付ける記録帳が作られます。
キーはstring型なので、リク、ソラ、レンのような文字列を指定できます。
値はint型なので、100、80、76のような整数を保存できます。
mapへ値を登録する
mapへ値を登録するときは、キーを指定して値を代入します。
trainingScore["リク"] = 100;
trainingScore["ソラ"] = 80;
trainingScore["レン"] = 76;この3行によって、trainingScoreの中に次の対応が作られます。
| キー | 値 |
|---|---|
| リク | 100 |
| ソラ | 80 |
| レン | 76 |
キーは、値を探すための名前です。
値は、キーに対応して保存されるデータです。
リクというキーには100が対応します。
ソラというキーには80が対応します。
レンというキーには76が対応します。
ドラゴンボール風に言えば、神殿の修行記録帳に、戦士名と得点を書き込んでいる状態です。
図:mapの宣言と値の登録

この図が示していること
この図では、mapの宣言と値の登録の流れを表しています。
map<string, int> trainingScore と宣言することで、文字列をキーにして整数を保存できるmapを作ります。
そのあと、trainingScore[リク] = 100 のように、キーと値の対応を登録します。
mapでは、キーと値を1組として管理することが大切です。
mapから値を取り出す
mapから値を取り出すときも、キーを指定します。
trainingScore["リク"]この書き方で、リクに対応する値を取り出せます。
今回のサンプルでは、リクには100が登録されているため、trainingScore["リク"] の値は100になります。
表示するときは、次のように書けます。
cout << "リクの修行得点は" << trainingScore["リク"] << "点です。" << endl;この1行によって、リクの修行得点は100点です。と表示されます。
同じように、ソラやレンの値も取り出せます。
cout << "ソラの修行得点は" << trainingScore["ソラ"] << "点です。" << endl;
cout << "レンの修行得点は" << trainingScore["レン"] << "点です。" << endl;mapでは、キーを使うことで、目的の値へ直接アクセスできます。
配列のように0番目、1番目という番号を意識する必要がないため、データの意味が読み取りやすくなります。
mapの仕組みをイメージする
mapは、キーと値の対応表です。
今回のtrainingScoreは、次のような状態になっています。
trainingScore
リク → 100
ソラ → 80
レン → 76この対応表があるため、キーを指定すると値を取り出せます。
リクを指定すれば100が取り出せます。
ソラを指定すれば80が取り出せます。
レンを指定すれば76が取り出せます。
この考え方は、実際のプログラムでもとてもよく使われます。
たとえば、技名から消費気力を調べたり、アイテム名から所持数を調べたり、流派名から修行回数を調べたりできます。
| 管理したい情報 | キー | 値 |
|---|---|---|
| 戦士の修行得点 | 戦士名 | 得点 |
| 技の消費気力 | 技名 | 消費気力 |
| アイテムの所持数 | アイテム名 | 個数 |
| 流派ごとの修行回数 | 流派名 | 回数 |
mapは、何かの名前と、それに対応するデータを結び付けたい場面に向いています。
mapで同じキーに代入した場合
mapでは、同じキーにもう一度値を代入すると、値が上書きされます。
たとえば、次のように書いたとします。
trainingScore["リク"] = 100;
trainingScore["リク"] = 120;この場合、リクに対応する値は、最終的に120になります。
最初に100を登録していますが、そのあと同じキーで120を代入しているため、値が更新されます。
これは、修行得点を更新する場面では便利です。
リクが追加修行を行い、得点が100点から120点へ上がった、というように考えると自然です。
| 処理 | リクの値 |
|---|---|
| trainingScore["リク"] = 100 | 100 |
| trainingScore["リク"] = 120 | 120 |
同じキーは、同じ記録欄を表します。
そのため、同じキーに値を入れ直すと、その記録欄の内容が変わります。
mapの主なメンバ関数
mapには、データを管理するための便利なメンバ関数があります。
| メンバ関数 | 役割 |
|---|---|
| clear | すべての要素を消去する |
| empty | mapが空かどうかを調べる |
| erase | 指定したキーの要素を削除する |
| size | 要素数を取得する |
| find | 指定したキーを探す |
clearを使うと、mapの中身をすべて消去できます。
emptyを使うと、mapが空かどうかを確認できます。
eraseを使うと、指定したキーの要素を削除できます。
sizeを使うと、mapに登録されている要素数を取得できます。
findを使うと、指定したキーがmapの中にあるかを探せます。
たとえば、trainingScoreの要素数を調べたい場合は、sizeを使います。
cout << trainingScore.size() << endl;ソラの記録を削除したい場合は、eraseを使います。
trainingScore.erase("ソラ");すべての記録を消したい場合は、clearを使います。
trainingScore.clear();mapが空かどうかを調べたい場合は、emptyを使います。
if (trainingScore.empty()) {
cout << "修行記録は空です。" << endl;
}findでキーを探す
mapでは、キーを指定して値を取り出せます。
ただし、指定したキーが本当に存在するかを確認したい場合もあります。
そのようなときに使えるのがfindです。
findは、指定したキーを探し、見つかった場合はその位置を表すイテレータを返します。
見つからなかった場合は、endを返します。
map<string, int>::iterator itr;
itr = trainingScore.find("レン");
if (itr != trainingScore.end()) {
cout << "レンの修行得点は" << itr->second << "点です。" << endl;
}
else {
cout << "レンの修行記録は見つかりませんでした。" << endl;
}mapのイテレータでは、キーをfirst、値をsecondで扱います。
itr->first
itr->seconditr->first はキーを表します。
itr->second は値を表します。
今回の場合、レンが見つかれば、itr->first はレン、itr->second は76になります。
findを使うと、キーが存在するかどうかを確認してから値を扱えるため、より安全にmapを使えます。
図:mapの主な操作

この図が示していること
この図では、mapでよく使う主な操作を表しています。
sizeで要素数を確認し、findでキーを探し、eraseで指定キーの要素を削除できます。
emptyで空かどうかを調べ、clearですべての要素を消去できます。
mapは、キーと値の対応を登録するだけでなく、登録済みのデータを調べたり削除したりする機能も持っています。
vector、list、mapの使い分け
ここまで学んできたSTLのコンテナには、それぞれ得意なことがあります。
vectorは、番号で要素へアクセスしたいときに向いています。
listは、先頭や途中への挿入、要素の削除など、隊列を組み替えたいときに向いています。
mapは、キーから値を探したいときに向いています。
| コンテナ | 得意なこと | ドラゴンボール風のイメージ |
|---|---|---|
| vector | 番号で要素を管理する | 番号付きの修行データボード |
| list | 並びの変更や削除を行う | 戦士の隊列 |
| map | キーから値を探す | 名前で探せる修行記録帳 |
たとえば、入力された順番に戦闘力を保存するならvectorが分かりやすいです。
戦士の並びを途中で入れ替えるならlistが考えやすいです。
戦士名から修行得点を取り出すならmapが向いています。
STLでは、どのコンテナを使うかによって、プログラムの考え方が変わります。
大切なのは、データをあとでどのように使いたいかを考えて選ぶことです。
連想配列としてのmapで身につけたい感覚
mapは、番号ではなくキーで値を取り出すためのSTLコンテナです。
vectorのように0番目、1番目、2番目という番号で管理するのではなく、リク、ソラ、レンのような名前で値を探せます。
今回のサンプルでは、戦士名をキーにして、修行得点を値として保存しました。
リク → 100
ソラ → 80
レン → 76このような対応関係を作れることが、mapの大きな特徴です。
ドラゴンボール風に言えば、mapは神殿の修行記録帳です。
戦士名を調べると、その戦士の得点がすぐに分かります。
技名を調べると、その技の威力や消費気力が分かるようにもできます。
mapを使えるようになると、名前と値を結び付けるデータ管理がとても書きやすくなります。
戦士名と点数、技名と威力、アイテム名と所持数、流派名と修行回数のように、何かと何かを対応させたいときはmapが役立ちます。
C++でデータを扱うとき、順番で管理するだけではなく、意味のあるキーで管理できるようになると、プログラムの表現力が大きく広がります。
