如何在 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 起已过时 - 您可以使用 ranged based for loop 并简单地执行以下操作:
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(auto iterator = m.begin(); iterator != m.end(); iterator++)
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;
}
}
使用 C++17(或更高版本),您可以使用“结构化绑定”功能,它允许您使用单个元组/对定义多个具有不同名称的变量。例子:
for (const auto& [name, description] : planet_descriptions) {
std::cout << "Planet " << name << ":\n" << description << "\n\n";
}
original proposal(由杰出人物 Bjarne Stroustrup、Herb Sutter 和 Gabriel Dos Reis 撰写)读起来很有趣(而且建议的语法更直观,恕我直言);还有 proposed wording for the standard 读起来很无聊,但更接近实际内容。
做这样的事情:
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++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
正如 their answer 中提到的 einpoklum,由于 C++17,您也可以使用 structured binding declarations。我想通过提供一个完整的解决方案来扩展这一点,以一种舒适的方式迭代地图:
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;
}
输出:
m[name1][value1]=data1 m[name1][value2]=data2 m[name2][value1]=data1 m[name2][value2]=data2 m[name3][value1]=data1 m[name3][值2]=数据2
注 1: 为了填充地图,我使用了 initializer list(这是一个 C++11 功能)。这有时可以方便地保持固定初始化的紧凑性。
注意 2: 如果要在循环中修改地图 m
,则必须删除 const
关键字。
当 map 为 const 时使用 std::map< std::string, std::map<std::string, std::string> >::const_iterator
。
auto
兄弟,否则使用 vim 的人会被 KO。
第一个解决方案是使用 range_based for 循环,例如:
注意:当 range_expression
的类型为 std::map
时,range_declaration
的类型为 std::pair
。
for ( range_declaration : range_expression )
//loop_statement
代码 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
}
}
第二种解决方案:
代码 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
}
}
不定期副业成功案例分享
auto
之后写const
的决定有什么关系吗?纯粹是审美吗?int const *x
和int *const x
时,您可以将其写为int const *const x
,这比const int *const x
更清晰 IMO。但它只是从左到右解析,所以效果是一样的。查看此问题的答案:stackoverflow.com/questions/5503352/const-before-or-const-after