C++でstd::map
をループするにはどうすればいいですか?私の地図は次のように定義されています:
std::map< std::string, std::map<std::string, std::string> >
たとえば、上記のコンテナは次のようなデータを保持しています。
m["name1"]["value1"] = "data1";
m["name1"]["value2"] = "data2";
m["name2"]["value1"] = "data1";
m["name2"]["value2"] = "data2";
m["name3"]["value1"] = "data1";
m["name3"]["value2"] = "data2";
このマップをループしてさまざまな値にアクセスするにはどうすればよいですか。
古い質問ですが、残りの答えはC++ 11の時点では古くなっています - の範囲をベースにしたループを使用することができます そして単に次のようにします。
std::map<std::string, std::map<std::string, std::string>> mymap;
for(auto const &ent1 : mymap) {
// ent1.first is the first key
for(auto const &ent2 : ent1.second) {
// ent2.first is the second key
// ent2.second is the data
}
}
これは以前のバージョンよりはるかにクリーンであるべきであり、そして不必要なコピーを避けます。
コメントを参照変数の明示的な定義(未使用の場合は最適化される)で置き換えることを好む人もいます。
for(auto const &ent1 : mymap) {
auto const &outer_key = ent1.first;
auto const &inner_map = ent1.second;
for(auto const &ent2 : inner_map) {
auto const &inner_key = ent2.first;
auto const &inner_value = ent2.second;
}
}
イテレータを使うことができます。
typedef std::map<std::string, std::map<std::string, std::string>>::iterator it_type;
for(it_type iterator = m.begin(); iterator != m.end(); iterator++) {
// iterator->first = key
// iterator->second = value
// Repeat if you also want to iterate through the second map.
}
for(std::map<std::string, std::map<std::string, std::string> >::iterator outer_iter=map.begin(); outer_iter!=map.end(); ++outer_iter) {
for(std::map<std::string, std::string>::iterator inner_iter=outer_iter->second.begin(); inner_iter!=outer_iter->second.end(); ++inner_iter) {
std::cout << inner_iter->second << std::endl;
}
}
またはC++ 0xでより良い:
for(auto outer_iter=map.begin(); outer_iter!=map.end(); ++outer_iter) {
for(auto inner_iter=outer_iter->second.begin(); inner_iter!=outer_iter->second.end(); ++inner_iter) {
std::cout << inner_iter->second << std::endl;
}
}
このようなことをしなさい:
typedef std::map<std::string, std::string> InnerMap;
typedef std::map<std::string, InnerMap> OuterMap;
Outermap mm;
...//set the initial values
for (OuterMap::iterator i = mm.begin(); i != mm.end(); ++i) {
InnerMap &im = i->second;
for (InnerMap::iterator ii = im.begin(); ii != im.end(); ++ii) {
std::cout << "map["
<< i->first
<< "]["
<< ii->first
<< "] ="
<< ii->second
<< '\n';
}
}
C++ 17では、「構造化バインディング」機能を使用できるようになります。これにより、単一のTuple /ペアを使用して、異なる名前で複数の変数を定義できます。例:
for (const auto& [name, description] : planet_descriptions) {
std::cout << "Planet " << name << ":\n" << description << "\n\n";
}
オリジナルの提案 (著名人Bjarne Stroustrup、Herb Sutter、Gabriel Dos Reisによる)は読むのが楽しいです(そして推奨される構文はもっと直感的な私見です)。 提案されている標準の文言もあります 読むのは退屈ですが、実際に行われるものに近いです。
C++ 11:
std::map< std::string, std::map<std::string, std::string> > m;
m["name1"]["value1"] = "data1";
m["name1"]["value2"] = "data2";
m["name2"]["value1"] = "data1";
m["name2"]["value2"] = "data2";
m["name3"]["value1"] = "data1";
m["name3"]["value2"] = "data2";
for (auto i : m)
for (auto j : i.second)
cout << i.first.c_str() << ":" << j.first.c_str() << ":" << j.second.c_str() << endl;
出力:
name1:value1:data1
name1:value2:data2
name2:value1:data1
name2:value2:data2
name3:value1:data1
name3:value2:data2
mapがconstのときはstd::map< std::string, std::map<std::string, std::string> >::const_iterator
を使います。
彼らの答え で述べたeinpoklumのように、 C++ 17 以降では、 構造化バインディング宣言 を使うこともできます。私はこれを拡張して、快適な方法でマップのマップを反復処理するための完全なソリューションを提供します。
int main() {
std::map<std::string, std::map<std::string, std::string>> m {
{"name1", {{"value1", "data1"}, {"value2", "data2"}}},
{"name2", {{"value1", "data1"}, {"value2", "data2"}}},
{"name3", {{"value1", "data1"}, {"value2", "data2"}}}
};
for (const auto& [k1, v1] : m)
for (const auto& [k2, v2] : v1)
std::cout << "m[" << k1 << "][" << k2 << "]=" << v2 << std::endl;
return 0;
}
注1:マップを埋めるために、 初期化子リスト (これは C++ 11 機能です)を使用しました。これは、固定初期化をコンパクトに保つために便利な場合があります。
注2:ループ内でマップm
を変更したい場合は、const
キーワードを削除する必要があります。