2011-01-30 2 views
266

Как бы я прошел через std::map в C++? Моя карта определяется как:Как перемещаться по карте карт C++?

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

Как я могу перебрать эту карту и получить доступ к различным значения?

+21

Возможно, вам стоит принять ответ Riot на современный C++, сделать это для гуглеров. –

+0

Не совсем уверен, что карта карт будет [минимальным, полным, проверенным] (http://stackoverflow.com/help/mcve) примером, но точка сделана! – davidhood2

+3

В случае, если вы пропустили уведомление, позвольте мне повторить комментарий chuckleplant: ** Вы можете подумать о принятии ответа Riot на современный C++, сделать это для гуглеров. ** –

ответ

530

Старый вопрос, но остальные ответы устарели, как в 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; 
    } 
} 
+13

Поддержки для хранения соответствующих ответов - я только хочу, чтобы это могло приблизиться к вершине. Возможно, было бы целесообразно изменить это в соответствии с принятым ответом? (Это то, что мы делаем на TeX.SX, но SO - это другая культура.) –

+2

Просто быстрый вопрос, есть ли какое-либо отношение к вашему решению написать 'const' после' auto'? Это чисто эстетический? – Parham

+6

@Parham const до или после указанного типа является предпочтительным, но я предпочитаю держать его справа, потому что он делает его более ясным в ситуациях, когда используются указатели; например, при использовании как '' 'int const * x''', так и' '' int * const x''' вы можете записать его как '' 'int const * const x''', который намного более ясный IMO, чем' ' 'const int * const x'''. Но это просто анализируется слева направо, поэтому эффект тот же. См. Ответы на этот вопрос: http://stackoverflow.com/questions/5503352/const-before-or-const-after – Riot

304

Вы можете использовать итератор.

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. 
} 
+0

это работает красиво, но делает cout << it_type-> первый << endl; дает мне ожидаемое первичное выражение перед ожиданием -> токен – Jack

+2

Это потому, что it_type - это тип, а 'iterator' - переменная. Виноват. – Puppy

+0

А не беспокойтесь. Я должен это заметить.Спасибо в любом случае – Jack

58
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; 
    } 
} 
+13

+1 для обеспечения обеих версий. Должен любить 'auto'. – Xeo

+2

Вы должны использовать auto &, или если вы не изменяете карту, даже const auto &. Кроме того, предпочитайте не-член begin() и end(), то есть для (const auto & iter = begin (map); ...). – Ela782

+13

Или даже проще: для (const auto & element: map) cout << element.second; – Ela782

23

ли что-то вроде этого:

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'; 
    } 
} 
+0

Во втором случае это должно быть ++ ii not ++ i :) – Slipstream

+0

Я думаю, что '/ n' должно быть '\ n' в конце –

+0

Ну, я бы использовал определения, чтобы позже их определить. Это хороший способ для C++ 98 :) +1 –

1

использование std::map< std::string, std::map<std::string, std::string> >::const_iterator когда карта Уст.

+1

Вы знаете , иногда не является хорошей привычкой скрывать код за правой границей. Я понимаю, что это безопаснее, но я полностью скрываю видение кода. Идите '' 'auto''' bro, или тот, кто использует vim, отправится KO. –

11

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 
+1

Как этот ответ отличается от http://stackoverflow.com/a/27344958/3658660? За исключением того факта, что он делает копии повсюду. –

20

В C++ 17, вы будете иметь возможность использовать "структурированные привязок" функцию, которая позволяет определить несколько переменных , с разными именами, используя один кортеж/пару. Пример:

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

original proposal (корифеями Бьярне Страуструп, травы Sutter и Габриэль Dos Reis) интересно читать (и предлагаемый синтаксис более интуитивным ИМХО); есть также proposed wording for the standard, который скучно читать, но ближе к тому, что на самом деле зайдет.

+2

Это так мило, что мне нужно проголосовать, несмотря на то, что C++ 17 еще не «там». Человек, они действительно оживляют C++, упрощая запись чистого и безопасного кода. – Jonas

+0

@ Jonas: C++ 17 теперь «там». – einpoklum

Смежные вопросы