297

How can I loop through a std::map in C++? My map is defined as:

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

For example, the above container holds data like this:

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

How can I loop through this map and access the various values?

honk
  • 9,137
  • 11
  • 75
  • 83
Jack
  • 3,769
  • 6
  • 24
  • 32

9 Answers9

578

Old question but the remaining answers are outdated as of C++11 - you can use a ranged based for loop and simply do:

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

this should be much cleaner than the earlier versions, and avoids unnecessary copies.

Some favour replacing the comments with explicit definitions of reference variables (which get optimised away if unused):

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

Update for C++17: it is now possible to simplify this even further using structured bindings, as follows:

for(auto const &[outer_key, inner_map] : mymap) {
  for(auto const &[inner_key, inner_value] : inner_map) {
    // access your outer_key, inner_key and inner_value directly
  }
}
Riot
  • 15,723
  • 4
  • 60
  • 67
  • 13
    Props for keeping the answers relevant -- I only wish this could rise its way nearer to the top. Perhaps editing this in to the accepted answer would be appropriate? (It's what we do on TeX.SX, but SO is a different culture.) – Sean Allred Dec 12 '14 at 15:33
  • 2
    Just a quick question, is there any relevance to your decision of writing `const` after `auto`? Is it purely aesthetic? – Parham Dec 30 '14 at 08:59
  • 6
    @Parham const before or after a type specified is a matter of preference, but I choose to keep it on the right because it makes it clearer in situations where pointers are being used; for instance when using both ```int const *x``` and ```int *const x``` you can write it as ```int const *const x``` which is much clearer IMO than ```const int *const x```. But it's just parsed from left to right so the effect is the same. See the answers to this question: http://stackoverflow.com/questions/5503352/const-before-or-const-after – Riot Dec 30 '14 at 12:34
  • 2
    what does the & mean in the auto const &ent2? – Tanner Summers Apr 09 '16 at 08:00
  • 1
    @TannerSummers this is accessing each member by const reference, rather than by value. – Riot Apr 09 '16 at 09:11
  • 1
    @Riot can you explain why this would be needed? – Tanner Summers Apr 09 '16 at 17:11
  • 5
    @TannerSummers because accessing by value would add the inefficiency of copying each element; additionally if you wanted to modify the contents, you'd need to access the elements by references (or pointers) rather than by value. – Riot Apr 10 '16 at 07:51
  • @Riot Thats a really helpful technicality I've never heard before (in the year I've been doing c++) - if you pass any member object as "object&" does it access the original and if you pass "object" it accesses an exact copy...? – davidhood2 Nov 02 '16 at 19:23
  • 2
    @davidhood2 passing anything without either & for a reference or * for a pointer is making a copy, yes. – Riot Nov 02 '16 at 20:46
  • 1
    Have a look, also, at this syntax `for (auto&& [first,second] : mymap)` [here](http://en.cppreference.com/w/cpp/language/range-for) – Brent Bradburn Feb 26 '18 at 05:17
311

You can use an iterator.

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.
}
Puppy
  • 144,682
  • 38
  • 256
  • 465
  • that works nicely, but doing cout << it_type->first << endl; gives me the error expected primary-expression before -> token – Jack Jan 30 '11 at 19:29
  • 2
    That's becaus it_type is the type, and `iterator` is the variable. My mistake. – Puppy Jan 30 '11 at 19:36
  • Ah no worries. I should of spotted that. Thanks anyway – Jack Jan 30 '11 at 19:37
  • 10
    Unless he intends to modify the map, using const_iterator would be better. – Michael Aaron Safyan Jan 30 '11 at 20:14
  • 29
    it is more efficient to do ++iterator than iterator++ since it avoids an unnecessary copy when incrementing. – Game_Overture Oct 11 '13 at 03:39
  • 19
    Using auto greatly simplifies the loop for C++11 : `for(auto iterator = m.begin(); iterator != m.end(); iterator++)` – Gerard Apr 30 '14 at 12:36
  • 127
    This is pretty outdated for c++11. Just use for (auto iter : mymap) – Anonymous Entity May 23 '14 at 16:28
  • 1
    @Balk there is no performance difference whatsoever. Unless there is something amiss with the compiler, the assembly code will be identical. – quant Jul 13 '14 at 00:19
  • 38
    For c++11, you should use (auto& iter : mymap) to avoid the potential copy. – dev_nut Nov 15 '14 at 21:54
  • @user11177 docs I'm seeing say that in the range_expression that `auto` variable will have the type of `*iterator` and will not itself be an iterator? – Alnitak Dec 09 '14 at 09:24
  • 3
    @user11177: You get a pair, not an iterator, if you do that, so it should be `for (auto& entry : mymap)` – Claudiu Jul 14 '15 at 15:53
  • 3
    @quant _maybe_, but why take the risk when it's totally unnecessary and semantically grating? the fact that almost everyone seems to default to postincrement/decrement is a terrible habit, which is pointless unless the pre temporary is actually needed for something. I assume the blame for this pervasive trend lies with the terrible decision to call the language C++ instead of ++C - as if C had been made better, but the better version was thrown away, and we got a copy of the original instead, heh. – underscore_d Dec 18 '15 at 12:56
60
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;
    }
}

or nicer in 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;
    }
}
Axel Gneiting
  • 5,293
  • 25
  • 30
  • 2
    You should use auto&, or if you don't modify the map, even const auto&. In addition, prefer the non-member begin() and end(), i.e. for(const auto& iter = begin(map); ...). – Ela782 Apr 04 '14 at 23:41
  • 13
    Or even simpler: for(const auto& element : map) cout << element.second; – Ela782 Apr 04 '14 at 23:43
28

With C++17 (or later), you can use the "structured bindings" feature, which lets you define multiple variables, with different names, using a single tuple/pair. Example:

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

The original proposal (by luminaries Bjarne Stroustrup, Herb Sutter and Gabriel Dos Reis) is fun to read (and the suggested syntax is more intuitive IMHO); there's also the proposed wording for the standard which is boring to read but is closer to what will actually go in.

einpoklum
  • 118,144
  • 57
  • 340
  • 684
  • 2
    This is so pretty I need to vote despite C++17 not being "there" quite yet. Man, they're really revitalizing C++ by making it easier to write clean and safe code. – Jonas Feb 07 '17 at 13:38
24

Do something like this:

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';
    }
}   
Kevin Reid
  • 37,492
  • 13
  • 80
  • 108
12

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;

output:

name1:value1:data1
name1:value2:data2
name2:value1:data1
name2:value2:data2
name3:value1:data1
name3:value2:data2
user1438233
  • 1,153
  • 1
  • 14
  • 30
  • 2
    How this answer is different from http://stackoverflow.com/a/27344958/3658660 ? Except for the fact that it's making copies everywhere. – hlscalon Nov 28 '16 at 13:33
4

As einpoklum mentioned in their answer, since C++17 you can also use structured binding declarations. I want to extend on that by providing a full solution for iterating over a map of maps in a comfortable way:

int main() {
    std::map<std::string, std::map<std::string, std::string>> m {
        {"name1", {{"value1", "data1"}, {"value2", "data2"}}},
        {"name2", {{"value1", "data1"}, {"value2", "data2"}}},
        {"name3", {{"value1", "data1"}, {"value2", "data2"}}}
    };

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

    return 0;
}

Output:

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

Note 1: For filling the map, I used an initializer list (which is a C++11 feature). This can sometimes be handy to keep fixed initializations compact.

Note 2: If you want to modify the map m within the loops, you have to remove the const keywords.

Code on Coliru

honk
  • 9,137
  • 11
  • 75
  • 83
1

use std::map< std::string, std::map<std::string, std::string> >::const_iterator when map is const.

Amir Saniyan
  • 13,014
  • 20
  • 92
  • 137
  • 1
    You know, it is sometimes not a good habit to hide code behind the right margin. I understand it's safer but well il completely blur the vision of the code. Go ```auto``` bro, or he who uses vim will go KO. – Ludovic Zenohate Lagouardette Feb 12 '16 at 13:14
0

First solution is Use range_based for loop, like:

Note: When range_expression’s type is std::map then a range_declaration’s type is std::pair.

for ( range_declaration : range_expression )      
  //loop_statement

Code 1:

typedef std::map<std::string, std::map<std::string, std::string>> StringToStringMap;

StringToStringMap my_map;

for(const auto &pair1 : my_map) 
{
   // Type of pair1 is std::pair<std::string, std::map<std::string, std::string>>
   // pair1.first point to std::string (first key)
   // pair1.second point to std::map<std::string, std::string> (inner map)
   for(const auto &pair2 : pair1.second) 
   {
       // pair2.first is the second(inner) key
       // pair2.second is the value
   }
}

The Second Solution:

Code 2

typedef std::map<std::string, std::string> StringMap;
typedef std::map<std::string, StringMap> StringToStringMap;

StringToStringMap my_map;

for(StringToStringMap::iterator it1 = my_map.begin(); it1 != my_map.end(); it1++)
{
    // it1->first point to first key
    // it2->second point to inner map
    for(StringMap::iterator it2 = it1->second.begin(); it2 != it1->second.end(); it2++)
     {
        // it2->second point to value
        // it2->first point to second(inner) key 
     }
 }
AmirSalar
  • 325
  • 2
  • 14