如何循环遍历一个C++ map of maps?

o2gm4chl  于 2023-03-14  发布在  其他
关注(0)|答案(9)|浏览(363)

如何在C++中循环遍历std::map?我的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";

如何循环遍历这个Map并访问不同的值?

envsm3lx

envsm3lx1#

旧问题,但其余的答案在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;
  }
}

针对C++17的更新:现在可以使用结构化绑定来进一步简化这一点,如下所示:

for(auto const &[outer_key, inner_map] : mymap) {
  for(auto const &[inner_key, inner_value] : inner_map) {
    // access your outer_key, inner_key and inner_value directly
  }
}
kyvafyod

kyvafyod2#

可以使用迭代器。

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.
}
7fhtutme

7fhtutme3#

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;
    }
}
sr4lhrrt

sr4lhrrt4#

在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,读起来很无聊,但更接近实际内容。

vh0rcniy

vh0rcniy5#

请执行以下操作:

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';
    }
}
blmhpbnm

blmhpbnm6#

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
ipakzgxi

ipakzgxi7#

正如在their answer中提到的 einpoklum,由于C++17,你也可以使用structured binding declarations。我想通过提供一个完整的解决方案来扩展它,以一种舒适的方式迭代Map的Map:

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[名称1][值1]=数据1
m[名称1][值2]=数据2
m[名称2][值1]=数据1
m[名称2][值2]=数据2
m[名称3][值1]=数据1
m[名称3][值2]=数据2

  • 注1:* 为了填充Map,我使用了一个initializer list(这是C++11的一个特性),这有时可以方便地保持固定初始化的紧凑性。
  • 注2:* 如果您想修改循环中的Mapm,则必须删除const关键字。

Code on Coliru

x9ybnkn6

x9ybnkn68#

Map恒定时使用std::map< std::string, std::map<std::string, std::string> >::const_iterator

fcipmucu

fcipmucu9#

第一个解决方案是使用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 
     }
 }

相关问题