Comment puis-je parcourir un std::map
en C++? Ma carte est définie comme:
std::map< std::string, std::map<std::string, std::string> >
Par exemple, le conteneur ci-dessus contient des données telles que:
m["name1"]["value1"] = "data1";
m["name1"]["value2"] = "data2";
m["name2"]["value1"] = "data1";
m["name2"]["value2"] = "data2";
m["name3"]["value1"] = "data1";
m["name3"]["value2"] = "data2";
Comment puis-je parcourir cette carte et accéder aux différentes valeurs?
Ancienne question mais les réponses restantes sont obsolètes à partir de C++ 11 - vous pouvez utiliser un basé sur pour la boucle et simplement faire:
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
}
}
cela devrait être beaucoup plus propre que les versions précédentes et éviter les copies inutiles.
Certains préfèrent remplacer les commentaires par des définitions explicites de variables de référence (qui sont optimisées si elles ne sont pas utilisées):
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;
}
}
Vous pouvez utiliser un itérateur.
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;
}
}
ou plus agréable en 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;
}
}
Faites quelque chose comme ça:
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';
}
}
En C++ 17, vous pourrez utiliser la fonctionnalité "liaisons structurées", qui vous permet de définir plusieurs variables, avec des noms différents, à l'aide d'un seul tuple/paire. Exemple:
for (const auto& [name, description] : planet_descriptions) {
std::cout << "Planet " << name << ":\n" << description << "\n\n";
}
La proposition originale (par les luminaires Bjarne Stroustrup, Herb Sutter et Gabriel Dos Reis) est amusante à lire (et la syntaxe suggérée est plus intuitive à mon humble avis); il y a aussi le libellé proposé pour la norme qui est ennuyeux à lire mais qui est plus proche de ce qui va réellement se passer.
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;
sortie:
name1:value1:data1
name1:value2:data2
name2:value1:data1
name2:value2:data2
name3:value1:data1
name3:value2:data2
utilisez std::map< std::string, std::map<std::string, std::string> >::const_iterator
lorsque map est const.
Comme einpoklum mentionné dans leur réponse , puisque C++ 17 vous pouvez également utiliser des déclarations de liaison structurées . Je souhaite approfondir ce sujet en fournissant une solution complète permettant de parcourir facilement une carte de cartes:
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;
}
Note 1: Pour remplir la carte, j'ai utilisé un initializer list (qui est un C++ 11 feature). Cela peut parfois être utile pour garder les initialisations fixes compactes.
Note 2: Si vous souhaitez modifier la carte m
au sein des boucles, vous devez supprimer les mots clés const
.