开发者

How can I iterate over an STL map inside an STL map?

I have an STL map definition as follows:

map<string, map<int, string&开发者_如何学Cgt; > info;

I iterate that map using the following code:

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

Is this the correct way to iterate or is there a better way to do so? The above code works for me, but I'm looking for a more elegant solution.


This is correct, it just lacks a few typedef and readability improvements :

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)
    {
        /* ... */
    }
}


If C++11 is available you may use range for loop:

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

If only C++11 auto is available:

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

If you may use BOOST there is 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 */
    }
}


While it's not clear what problem you are solving by having a map inside a map, I don't think there is a better way of iterating on all the items without using these iterators. The only thing you can do to improve code readability is to use typedefs on the template types.

However, won't it be a better idea to define your map as

multimap <string, MyClass>

where MyClass is defined as a pair of integer and a string, as well as a toString() method to dump the contents, etc?


If c++11 is available, we could use stl algorithm for_each and lambda functions to get a elegant solution

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

OUTERMAP theMapObject;
// populate the map object

// iterate the map object now

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


If you want to iterate through both maps, then the way you presented is the best way. Now, if there is something specific you want to do then you might be better with using a function from the algorithm header.


If you have access to C++11 features, then range-based for loops as proposed in Juraj Blaho's answer seem to be the most readable option to me. However, if C++17 is available to you, then you can use structured bindings together with those loops to further increase readability, as you can get rid of all first and second members:

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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜