如何在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已经过时了-你可以使用一个基于范围的for循环,简单地做:

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++ 11已经过时了-你可以使用一个基于范围的for循环,简单地做:

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

正如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;
}

输出:

m [name1] [value1] = data1 m [name1] [value2] =身份不明 m [name2] [value1] = data1 m [name2] [value2] =身份不明 m [name3] [value1] = data1 m [name3] [value2] =身份不明

注1:为了填充映射,我使用了初始化列表(这是c++ 11的特性)。这有时可以方便地保持固定的初始化紧凑。

注2:如果你想在循环中修改映射m,你必须删除const关键字。

Coliru上的代码

你可以这样做:

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(或更高版本)中,您可以使用“结构化绑定”特性,该特性允许您使用单个元组/对定义多个具有不同名称的变量。例子:

for (const auto& [name, description] : planet_descriptions) {
    std::cout << "Planet " << name << ":\n" << description << "\n\n";
}

最初的提议(由Bjarne Stroustrup, Herb Sutter和Gabriel Dos Reis撰写)读起来很有趣(我认为建议的语法更直观);此外,标准的提议措辞读起来很无聊,但更接近实际的内容。

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