std::map
はキーと値をペアで管理する連想配列です。
この記事では、初心者でもわかりやすくstd::map
の使い方について解説します。
std::mapとは
std::map
は、C++のSTL(Standard Template Library)に含まれるコンテナクラスの一つです。
キーと値をペアで保持することができ、キーを使って値を検索することができます。
例えば、以下のようなコードでstd::mapを宣言し、要素を追加することができます。
#include <iostream>
#include <map>
int main() {
std::map<std::string, int> myMap;
// 要素の追加
myMap["apple"] = 100;
myMap["banana"] = 200;
myMap["orange"] = 300;
// 要素の取得
std::cout << "apple: " << myMap["apple"] << std::endl; // 出力結果:apple: 100
std::cout << "banana: " << myMap["banana"] << std::endl; // 出力結果:banana: 200
std::cout << "orange: " << myMap["orange"] << std::endl; // 出力結果:orange: 300
return 0;
}
apple: 100
banana: 200
orange: 300
この例では、std::string型のキーとint型の値を持つstd::mapオブジェクトを宣言しています。
その後、[]演算子を使って要素を追加し、同じ演算子を使って要素を取得しています。
また、std::mapは自動的にキーに対して昇順ソートされます。これにより、キーに対して二分探索が可能になります。
std::mapの基本的な使い方
std::mapは、C++のSTL(Standard Template Library)に含まれるコンテナであり、キーと値をペアで格納することができます。この記事では、std::mapの基本的な使い方について解説します。
要素の追加
std::mapに要素を追加するには、insert()
メソッドを使用します。以下は、int型のキーとstring型の値を持つstd::mapに要素を追加する例です。
#include <iostream>
#include <map>
int main()
{
std::map<int, std::string> myMap;
// 要素の追加
myMap.insert(std::make_pair(1, "apple"));
myMap.insert(std::make_pair(2, "banana"));
myMap.insert(std::make_pair(3, "orange"));
return 0;
}
上記の例では、insert()メソッドを使用して3つの要素を追加しています。
make_pair()
関数は、引数として渡された2つの値からstd::pair
オブジェクトを作成し、それをinsert()
メソッドに渡すことで要素を追加しています。
要素の取得
std::map
では、キーに対応する値を取得する方法がいくつかあります。
at()関数を使用する方法
std::map
のat()
関数を使用すると、指定されたキーに対応する値を取得できます。例えば、以下のように記述します。
#include<iostream>
#include<map>
int main() {
std::map<std::string, int> mymap = { {"apple", 10}, {"orange", 20}, {"banana", 30} };
int value = mymap.at("apple");
std::cout << value;
return 0;
}
10
- []演算子を使用する方法
std::map
の[]
演算子を使用すると、指定されたキーに対応する値を取得できます。例えば、以下のように記述します。
#include<iostream>
#include<map>
int main() {
std::map<std::string, int> mymap = { {"apple", 10}, {"orange", 20}, {"banana", 30} };
int value = mymap["apple"];
std::cout << value;
return 0;
}
10
配列であれば、mymap[1]
のようにインデックスを指定しますが、std::map
ではキー名を指定することでそのキーが指す値を取得できます(キーがdouble型だとmymap[3.14]
というように指定することも可能です)。
要素の削除
std::map
から要素を削除するには、erase()
メソッドを使用します。以下は、先ほど作成したmyMap
からキーが2の要素を削除する例です。
#include <iostream>
#include <map>
int main()
{
std::map<int, std::string> myMap;
// 要素の追加
myMap.insert(std::make_pair(1, "apple"));
myMap.insert(std::make_pair(2, "banana"));
myMap.insert(std::make_pair(3, "orange"));
// 要素の削除
myMap.erase(2);
return 0;
}
上記の例では、erase()メソッドに削除したいキー(ここでは2)を渡すことで、そのキーに対応する要素が削除されます。
要素の検索
std::map
から特定のキーに対応する値を取得する場合は、find()
メソッドまたは[]
演算子を使用します。
以下は、先ほど作成したmyMapからキーが1の値(“apple”)を取得する例です。
#include <iostream>
#include <map>
int main()
{
std::map<int, std::string> myMap;
// 要素の追加
myMap.insert(std::make_pair(1, "apple"));
myMap.insert(std::make_pair(2, "banana"));
myMap.insert(std::make_pair(3, "orange"));
// キーが1に対応する値("apple")を取得
auto it = myMap.find(1);
if (it != myMap.end()) {
std::cout << it->second << std::endl; // 出力:apple
}
// []演算子でも同じ結果が得られる
std::cout << myMap[1] << std::endl; // 出力:apple
return 0;
}
apple
apple
上記の例では、find()メソッドでキーが1に対応するイテレータ(ポインタ)it を取得し、->
演算子でイテレータが指すペアオブジェクト({1,”apple”}) のsecond(value)部分、[]
演算子でも同じ結果が得られます。
std::mapの高度な使い方
前回は、std::mapの基本的な使い方について解説しました。今回は、より高度な使い方について解説します。
イテレータの利用
std::map
では、イテレータを使用することで要素を順番に取り出すことができます。イテレータを使用する場合は、以下のように記述します。
#include <iostream>
#include <map>
int main() {
std::map<int, std::string> m = {{1, "apple"}, {2, "banana"}, {3, "orange"}};
for (auto itr = m.begin(); itr != m.end(); ++itr) {
std::cout << itr->first << ": " << itr->second << std::endl;
}
return 0;
}
1: apple
2: banana
3: orange
上記のコードでは、std::mapに格納された要素を順番に取り出しています。
for文内で使用しているauto itr
は、イテレータ変数です。m.begin()
からm.end()
までループ処理を行っており、itr->first
とitr->second
でキーと値を取得しています。
要素のソート
std::map
では、キーまたは値で要素をソートすることができます。
キーでソートする場合はデフォルトで昇順になりますが、降順にしたい場合はgreater<>
を指定します。
値でソートする場合は、sort関数を使用して、どういう条件でソートするのかを定義した関数(ラムダ式)を渡してソートします。
#include <iostream>
#include <map>
#include <vector>
#include <string>
#include <algorithm>
int main() {
std::map<int, std::string> m1 = { {1, "banana"}, {3, "apple"}, {2, "orange"} };
// キーでソート(昇順)
for (auto i : m1) {
std::cout << i.first << " " << i.second << std::endl;
}
std::cout << std::endl;
// キーでソート(降順)
std::map<int, std::string, std::greater<>> m2(m1.begin(), m1.end());
for (auto i : m2) {
std::cout << i.first << " " << i.second << std::endl;
}
std::cout << std::endl;
// 値でソート(アルファベット順)
auto cmp = [](const auto& a, const auto& b) { return a.second < b.second; };
//mapだとキーでソートされてしまうのでvectorコンテナを使う
std::vector<std::pair<int, std::string>> v(m1.begin(), m1.end());
std::sort(v.begin(), v.end(), cmp);
for (auto i : v) {
std::cout << i.first << " " << i.second << std::endl;
}
return 0;
}
1: orange
2: banana
3: apple
3: apple
2: banana
1: orange
3 apple
2 banana
1 orange
上記のコードでは、キーまたは値で要素をソートしています。
キーが指す値でソートする場合、std::map
のままだと値でソートしてもキーで再ソートされてしまいますので、自動でソートされないstd::vector
など別のコンテナを使わないといけないので注意しましょう。
要素の比較
std::map
では、==
や!=
などの比較演算子を使って、2つのmapを比較することが可能です。
#include <iostream>
#include <map>
int main() {
std::map<int, std::string> a = { {1,"apple"},{2,"banana"} };
std::map<int, std::string> b = { {1,"apple"},{2,"banana"} };
if (a == b) {
std::cout << "a と b は同じキーと値を持っています。" << std::endl;
}
else {
std::cout << "a と b は何らかの異なるキー・値を持っています。" << std::endl;
}
if (a < b) {
std::cout << "a < b" << std::endl;
}
else {
std::cout << "a > b" << std::endl;
}
return 0;
}
a と b は同じキーと値を持っています。
a > b
std::mapの応用例
std::mapは、キーと値をペアで管理するデータ構造です。この特性を活かして、様々な応用例があります。
単語の出現回数のカウント
テキストファイルから単語を読み込み、各単語が何回出現したかをカウントするプログラムを考えてみましょう。
orange watermelon grape apple
melon grape apple watermelon
orange apple watermelon melon
#include <iostream>
#include <fstream>
#include <string>
#include <map>
int main() {
std::ifstream ifs("sample.txt");
std::string word;
std::map<std::string, int> count_map;
while (ifs >> word) {
++count_map[word];
}
for (const auto& pair : count_map) {
std::cout << pair.first << " : " << pair.second << std::endl;
}
return 0;
}
apple : 3
grape : 2
melon : 2
orange : 2
watermelon : 3
このプログラムでは、std::ifstream
クラスを使ってファイルから単語を読み込んでいます。
そして、std::map<std::string, int>
型の変数count_map
に対して、各単語が出現した回数をカウントしています。
最後に、for文でcount_map
の要素を順番に表示しています。
ユーザーのデータの管理
ユーザー名と年齢を管理するような、ユーザーデータの管理でもstd::map
が役立ちます。
#include <iostream>
#include <string>
#include <map>
struct User {
std::string name;
int age;
};
int main() {
std::map<int, User> user_map;
user_map[1] = {"Alice", 20};
user_map[2] = {"Bob", 25};
user_map[3] = {"Charlie", 30};
for (const auto& pair : user_map) {
const auto& key = pair.first;
const auto& value = pair.second;
std::cout << "key: " << key << ", name: " << value.name << ", age: " << value.age << std::endl;
}
return 0;
}
キー: 1 名前: Alice 年齢: 20
キー: 2 名前: Bob 年齢: 25
キー: 3 名前: Charlie 年齢: 30
このプログラムでは、User
という構造体を定義し、それぞれのユーザー情報(名前と年齢)を格納します。
そして、std::map<int, User>
型の変数user_map
に対して、ユーザーID(整数)とユーザー情報(構造体)をペアで格納します。最後にfor文で全ての要素を表示します。
その他の応用例
その他にも、以下のような応用例があります。
- グラフ理論:隣接リストや隣接行列などからグラフデータ構造を作成する場合に利用される。
- 集計処理:売上データやアクセスログなどから集計処理する場合に利用される。
- 統計処理:分布表や度数分布表などから統計処理する場合に利用される。