如何在 STL 映射中迭代 STL 映射?

Posted

技术标签:

【中文标题】如何在 STL 映射中迭代 STL 映射?【英文标题】:How can I iterate over an STL map inside an STL map? 【发布时间】:2011-05-29 19:48:52 【问题描述】:

我有一个 STL 映射定义如下:

map<string, map<int, string> > info;

我使用以下代码迭代该地图:

for( map<string, map<int, string> >::iterator ii=info.begin(); ii!=info.end(); ++ii)
    for(map<int, string>::iterator j=ii->second.begin(); j!=ii->second.end();++j)
        cout << (*ii).first << " : " << (*j).first << " : "<< (*j).second << endl;
    

这是正确的迭代方法还是有更好的方法?上面的代码对我有用,但我正在寻找更优雅的解决方案。

【问题讨论】:

要实际迭代外部映射和所有内部映射的所有条目,我会说没有“更好”的解决方案。两个嵌套循环,没问题。 作为一个关于优雅的附带问题,-&gt; 运算符有什么问题? 该代码没有任何错误或不雅点。只是我认为可能有更好的方法... 【参考方案1】:

这是正确的,只是缺少一些typedef 和可读性改进:

typedef std::map<int, std::string> inner_map;
typedef std::map<std::string, inner_map> outer_map;

for (outer_map::iterator i = outerMap.begin(), iend = outerMap.end(); i != iend; ++i)

    inner_map &innerMap = i->second;
    for (inner_map::iterator j = innerMap.begin(), jend = innerMap.end(); j != jend; ++j)
    
        /* ... */
    

【讨论】:

在这种情况下也可以使用 const 迭代器,并不是说它有很大的不同。【参考方案2】:

如果 C++11 可用,您可以使用 range for 循环:

for(auto &i: info) 
    for(auto &j: i.second) 
        /* */
    

如果只有 C++11 auto 可用:

for( auto i=info.begin(); i!=info.end(); ++i) 
   for( auto j=i->second.begin(); j!=i->second.end(); ++j) 
       /* */
   

如果您可以使用 BOOST,则有 BOOST_FOREACH:

typedef std::map<int, std::string> inner_map;
typedef std::map<std::string, inner_map> outer_map;

outer_map outer;

BOOST_FOREACH(outer_map::value_type &outer_value, outer)
    BOOST_FOREACH(inner_map::value_type &inner_value, outer_value->second)
        /* use outer_value and inner_value as std::pair */
    

【讨论】:

【参考方案3】:

虽然尚不清楚通过在地图中放置地图来解决什么问题,但我认为没有更好的方法可以在不使用这些迭代器的情况下迭代所有项目。提高代码可读性的唯一方法是在模板类型上使用 typedef。

但是,将map 定义为

multimap &lt;string, MyClass&gt;

其中MyClass被定义为一对整数和一个字符串,以及转储内容的toString()方法等?

【讨论】:

【参考方案4】:

如果 c++11 可用,我们可以使用 stl 算法 for_each 和 lambda 函数来获得一个优雅的解决方案

typedef map<int, string> INNERMAP;
typedef map<string, INNERMAP> OUTERMAP;

OUTERMAP theMapObject;
// populate the map object

// 现在迭代地图对象

std::for_each(theMapObject.cbegin(), theMapObject.cend(), 
    [](const OUTERMAP::value_type& outerMapElement)

    // process the outer map object
    const INNERMAP& innerMapObject = outerMapElement.second;
    std::for_each(innerMapObject.cbegin(), innerMapObject.cend(), 
        [](const INNERMAP::value_type& innermapElemen)
    
        //process the inner map element
    );
);

【讨论】:

【参考方案5】:

如果您想遍历这两个地图,那么您呈现的方式是最好的方式。现在,如果您想做一些特定的事情,那么使用算法头中的函数可能会更好。

【讨论】:

【参考方案6】:

如果您可以访问C++11 功能,那么Juraj Blaho's answer 中提出的range-based for loops 对我来说似乎是最易读的选项。但是,如果您可以使用C++17,那么您可以将structured bindings 与这些循环一起使用以进一步提高可读性,因为您可以摆脱所有firstsecond 成员:

std::map<std::string, std::map<int, std::string>> info;

for (const auto &[k1, v1] : info) 
    for (const auto &[k2, v2] : v1) 
        std::cout << k1 << " : " << k2 << " : " << v2 << std::endl;
    

Code on Coliru

【讨论】:

以上是关于如何在 STL 映射中迭代 STL 映射?的主要内容,如果未能解决你的问题,请参考以下文章

如何遍历STL映射(查找所有可能的对)

如何按值对 STL 映射进行排序?

迭代器类指南

递归 stl 映射

使用功能指针的STL映射

为啥 STL 在 find 上映射核心转储?