2011-01-30 36 views
266

¿Cómo puedo recorrer un std::map en C++? Mi mapa se define como:¿Cómo recorrer un mapa de mapas en C++?

std::map< std::string, std::map<std::string, std::string> > 

Por ejemplo, este posee los datos de la siguiente manera:

m["name1"]["value1"] = "data1"; 
m["name1"]["value2"] = "data2"; 
m["name2"]["value1"] = "data1"; 
m["name2"]["value2"] = "data2"; 
m["name3"]["value1"] = "data1"; 
m["name3"]["value2"] = "data2"; 

Como puedo bucle a través de este mapa y acceder a los diferentes valores?

+21

Puede considerar aceptar la respuesta de Riot para el C++ moderno, hágalo por los googlers. –

+0

No estoy del todo seguro de que un mapa de mapas sea un ejemplo [Mínimo, Completo, Verificable] (http://stackoverflow.com/help/mcve) pero el punto está hecho. – davidhood2

+3

En caso de que se haya perdido la notificación, permítame repetir el comentario de la chuckleplant: ** Puede considerar aceptar la respuesta de Riot para el C++ moderno, hágalo por los googlers. ** –

Respuesta

530

pregunta antiguo, pero las respuestas restantes son anticuados como de C++ 11 - puede usar un ranged based for loop y simplemente hacer:

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

esto debería ser mucho más limpio que las versiones anteriores, y evita copias innecesarias.

Algunos favorecen la sustitución de los comentarios con definiciones explícitas de variables de referencia (que conseguir optimizados de inmediato si no se utiliza):

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

Apoyos para mantener las respuestas relevantes - Solo me gustaría que esto se allane más y más hacia la cima. ¿Tal vez sería apropiado editar esto en la respuesta aceptada? (Es lo que hacemos en TeX.SX, pero SO es una cultura diferente.) –

+2

Solo una pregunta rápida, ¿hay alguna relevancia para su decisión de escribir 'const' después de' auto'? ¿Es puramente estético? – Parham

+6

@Parham const antes o después de un tipo especificado es una cuestión de preferencia, pero elijo mantenerlo a la derecha porque lo hace más claro en situaciones donde se usan punteros; por ejemplo, cuando se usan tanto '' 'int const * x''' como' '' int * const x''' se puede escribir como '' 'int const * const x''' que es mucho más claro que IMO' 'const int * const x'''. Pero solo se analiza de izquierda a derecha para que el efecto sea el mismo. Vea las respuestas a esta pregunta: http://stackoverflow.com/questions/5503352/const-before-or-const- after – Riot

304

Puede usar un iterador.

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

que funciona bien, pero al hacer cout << it_type-> primero << endl; me da el error esperado expresión primaria antes -> token – Jack

+2

Eso es porque it_type es el tipo, y 'iterator' es la variable. Mi error. – Puppy

+0

Ah, no te preocupes. Debería de haber visto eso.Gracias de todos modos – 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; 
    } 
} 

o más agradable en 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 para proporcionar ambas versiones. Tengo que amar 'auto'. – Xeo

+2

Debe usar auto &, o si no modifica el mapa, incluso const auto &. Además, prefiera el no miembro begin() y end(), es decir, para (const auto & iter = begin (map); ...). – Ela782

+13

O incluso más simple: for (const auto & element: map) cout << element.second; – Ela782

23

hacer algo como esto:

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

En el segundo debe ser ++ ii no ++ i :) – Slipstream

+0

Creo que el '/ n' debería ser un '\ n' al final –

+0

Bueno, yo habría utilizado define para undef más tarde, pero esta es una buena forma para C++ 98 :) +1 –

1

uso std::map< std::string, std::map<std::string, std::string> >::const_iterator cuando mapa es const.

+1

Usted sabe , a veces no es una buena costumbre esconder código detrás del margen derecho. Entiendo que es más seguro pero que borro por completo la visión del código. Ir '' 'auto''' hermano, o el que usa vim irá 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; 

de salida:

name1:value1:data1 
name1:value2:data2 
name2:value1:data1 
name2:value2:data2 
name3:value1:data1 
name3:value2:data2 
+1

¿Cómo esta respuesta es diferente de http://stackoverflow.com/a/27344958/3658660? Excepto por el hecho de que está haciendo copias en todas partes. –

20

En C++ 17, usted será capaz de utilizar la función de "fijaciones estructurados", que le permite definir múltiples variables , con diferentes nombres, usando una sola tupla/par. Ejemplo:

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

El original proposal (por luminarias Bjarne Stroustrup, Herb Sutter y Gabriel Dos Reis) es divertido de leer (y la sintaxis sugerida es mi humilde opinión más intuitivo); también está el proposed wording for the standard que es aburrido de leer, pero está más cerca de lo que realmente entrará.

+2

Esto es tan bonito que necesito votar a pesar de que C++ 17 todavía no está "allí". Hombre, realmente están revitalizando C++ al hacer más fácil escribir código limpio y seguro. – Jonas

+0

@Jonas: C++ 17 ahora está "allí". – einpoklum

Cuestiones relacionadas