How can I loop through a std::map
in C++? My map is defined as:
std::map< std::string, std::map<std::string, std::string> >
For example, the above container holds data like this:
m["name1"]["value1"] = "data1";
m["name1"]["value2"] = "data2";
m["name2"]["value1"] = "data1";
m["name2"]["value2"] = "data2";
m["name3"]["value1"] = "data1";
m["name3"]["value2"] = "data2";
How can I loop through this map and access the various values?
This question is related to
c++
loops
dictionary
iteration
idioms
With C++17 (or later), you can use the "structured bindings" feature, which lets you define multiple variables, with different names, using a single tuple/pair. Example:
for (const auto& [name, description] : planet_descriptions) {
std::cout << "Planet " << name << ":\n" << description << "\n\n";
}
The original proposal (by luminaries Bjarne Stroustrup, Herb Sutter and Gabriel Dos Reis) is fun to read (and the suggested syntax is more intuitive IMHO); there's also the proposed wording for the standard which is boring to read but is closer to what will actually go in.
You can use an iterator.
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.
}
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;
output:
name1:value1:data1
name1:value2:data2
name2:value1:data1
name2:value2:data2
name3:value1:data1
name3:value2:data2
Do something like this:
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';
}
}
As einpoklum mentioned in their answer, since C++17 you can also use structured binding declarations. I want to extend on that by providing a full solution for iterating over a map of maps in a comfortable way:
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: For filling the map, I used an initializer list (which is a C++11 feature). This can sometimes be handy to keep fixed initializations compact.
Note 2: If you want to modify the map m
within the loops, you have to remove the const
keywords.
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;
}
}
or nicer in 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;
}
}
First solution is Use range_based for loop, like:
Note: When range_expression
’s type is std::map
then a range_declaration
’s type is std::pair
.
for ( range_declaration : range_expression )
//loop_statement
Code 1:
typedef std::map<std::string, std::map<std::string, std::string>> StringToStringMap;
StringToStringMap my_map;
for(const auto &pair1 : my_map)
{
// Type of pair1 is std::pair<std::string, std::map<std::string, std::string>>
// pair1.first point to std::string (first key)
// pair1.second point to std::map<std::string, std::string> (inner map)
for(const auto &pair2 : pair1.second)
{
// pair2.first is the second(inner) key
// pair2.second is the value
}
}
The Second Solution:
Code 2
typedef std::map<std::string, std::string> StringMap;
typedef std::map<std::string, StringMap> StringToStringMap;
StringToStringMap my_map;
for(StringToStringMap::iterator it1 = my_map.begin(); it1 != my_map.end(); it1++)
{
// it1->first point to first key
// it2->second point to inner map
for(StringMap::iterator it2 = it1->second.begin(); it2 != it1->second.end(); it2++)
{
// it2->second point to value
// it2->first point to second(inner) key
}
}
use std::map< std::string, std::map<std::string, std::string> >::const_iterator
when map is const.
Source: Stackoverflow.com