Как я могу перебрать карту STL внутри карты STL? - PullRequest
11 голосов
/ 23 декабря 2010

У меня есть определение карты 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;
    }
}

Это правильный способ итерации или есть лучший способ сделать это? Приведенный выше код работает для меня, но я ищу более элегантное решение.

Ответы [ 6 ]

16 голосов
/ 23 декабря 2010

Это правильно, просто не хватает нескольких 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)
    {
        /* ... */
    }
}
12 голосов
/ 23 декабря 2010

Если доступен C ++ 11, вы можете использовать диапазон for loop:

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 */
    }
}
1 голос
/ 10 января 2013

Если доступен 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
    });
});
1 голос
/ 23 декабря 2010

Хотя неясно, какую проблему вы решаете, имея карту внутри карты, я не думаю, что есть лучший способ итерации по всем элементам без использования этих итераторов.Единственное, что вы можете сделать для улучшения читабельности кода, - это использовать typedef для типов шаблонов.

Однако не лучше ли будет определить map как

multimap <string, MyClass>

, где MyClass определяется как пара целых чисел и строка, а также метод toString () для вывода содержимого и т. Д.?

0 голосов
/ 20 марта 2019

Если у вас есть доступ к C ++ 11 функциям, то на основе диапазона для циклов , как предложено в Ответ Джураджа Блахо представляется наиболее читабельнымвариант для меня.Однако, если вам доступно C ++ 17 , вы можете использовать структурированные привязки вместе с этими циклами для дальнейшего повышения читабельности, поскольку вы можете избавиться от всех first иsecond члены:

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

Код на Coliru

0 голосов
/ 23 декабря 2010

Если вы хотите перебрать обе карты, то способ, который вы представили, является лучшим. Теперь, если вы хотите что-то конкретное, вам лучше использовать функцию из заголовка алгоритма.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...