1

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

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

For example, the above container holds data like this:

m["country"]["capital"] = value;
m["country1"]["capital1"] = value;
m["country2"]["capital2"] = value;

based on the country and capital,weather value gets updated

at present if and map is used

map<string,int>mp;                                                                                              
if(Albania)
map[Tirana]= weathervalue;
if("Algeria")
map["Algiers"] = weathervalue;

Any hints,indication and ideas to optimise is always welcome

lubgr
  • 37,368
  • 3
  • 66
  • 117
ann
  • 11
  • 3
  • Welcome to stackoverflow! Could you elaborate on how the first and the second map types are used together? The second example has `int` values, but in the second, it's `std::string`? – lubgr May 18 '21 at 08:27
  • sorry for typo mistake ,its actually std::map< std::string, std::map > – ann May 18 '21 at 08:31
  • Where does the input data come from? The strings and integers? – lubgr May 18 '21 at 08:32
  • weather (int) and capital (string) is obtained from the lower layer. for instance if the country received from the lower layer is algeria then for the capital of the country(locally) weather value is assigned(from lower layer) – ann May 18 '21 at 08:43
  • 1
    Ok but as what? `std::vector` and `std::vector`? You are asking for a loop over a map, but I think we also need to know where the data to be put into the map is living, in order to answer your question. – lubgr May 18 '21 at 08:44

2 Answers2

0
for(auto& it:mp){
   for(auto& it1: it.second){
        it1.second=weathervalue;
}

You can add conditions to this loops but this is the basic way of traversing map inside a map.

Basically map is a structure of key-value pairs so when traversing it you treat it as such. Nested map is the value part of the key-value pair of the original map and as such it is accessed as (name_of_iterator). second.

As m88 suggested: Adds to clarity of the code

  for(auto& [country,submap]:mp){
     for(auto& [capital,wetherValue]: submap){
          wetherValue=New_Weather_Value;
  }

Which is the feature of structured bindings added in C++17 standard.

Answer to the additional question.

  typedef map<string,int> mp; 
//note that you gave the alias mp to the map so you can not use it as as variable name
    void function(){
          int new_value=50; // some value
          mp::iterator inner; // iterator of inner map
          map<int,mp> mymap; // main map
          map<int,mp>::iterator outer; // iterator of the main map
          for (outer=mymap.begin();outer!=mymap.end();outer++){
            for(inner=outer->second.begin();inner!=outer->second.end();inner++)
               inner->second= new_value;
              //do some other stuff
           }
    
    }
//Additionally note that you must use the smart pointer in the case of nested maps

This is the one way but you can also use first two code snippets (since keyword auto detects the type of variable in use).

Marko
  • 138
  • 2
  • 11
  • 2
    Maybe even structured bindings if OP uses C++17, so it's easier to read. Something like `for (auto& [country, submap]: mp)` and `for (auto& [capital, weatherVal]: submap)`. – m88 May 18 '21 at 08:37
  • if the map is defined as below typedef map innermap; map outermap .. how to assign, access and loop through the same. – ann May 18 '21 at 09:16
  • Do you mean innermap in the second part? (mapoutermap) – Marko May 18 '21 at 09:26
  • @annmathew `map["foo"]` creates the entry if it doesn't exist and returns a reference on it. `map.at("foo")` throws an exception if it doesn't exists, or return a reference on it. `map.find("foo")` return an iterator on the entry, or `map.end()` if it doesn't exist. Check the doc: https://en.cppreference.com/w/cpp/container/map – m88 May 18 '21 at 09:28
  • thanks but how to access and how to loop through the same typedef map mp map outermap – ann May 18 '21 at 09:30
  • Both code snippets above should work anyway. It should be detected because of keyword auto.First iterator would be detected as key-value pair string-map and second as int,int. If it isn't nested map but just single map you can just delete the inner for loop and rename the binding for sake of convinience. – Marko May 18 '21 at 09:31
  • map ::iterator it map ::iterator inner_it for(it =mp.begin();it!=mp.end();it++)--- is throwing error – ann May 18 '21 at 09:34
  • Note that you didn't make the new map but instead redefined map as mp so intead of using map mymap it would be mp mymap and it wouldn't be map::iterator it but mp::iterator it etc.(you created the alias for that structure) – Marko May 18 '21 at 09:37
  • Error comes from the fact that you gave the alias mp to the map and then used it as a name of a variable.So if you want alias to be mp you can not name the map mp. So this should work: mp::iterator inner;map some_name; map::iterator outer for (outer=mymap.begin();outer!=mymap.end();outer++){} – Marko May 18 '21 at 09:41
  • there are 2 maps .... for instance based on the above use case map innermap ; mapoutermap – ann May 18 '21 at 09:43
  • mp::iterator inner;map some_name; map::iterator outer for (outer=mymap.begin();outer!=mymap.end();outer++){ for(inner=outer->second.begin();inner!=outer->second.end();inner++) inner.second= new_value;} – Marko May 18 '21 at 09:48
0

you can traverse like this

   std::map< std::string, std::map<std::string, int> > myMap;
    
    for(auto& iter : myMap)
    {
        for(auto& childIter : iter.second)
        {
            // do here what you want i.e
            if(childIter.first == "xyz")
            childIter.second = 20;
        }
    }
// OR
    for(auto& [country, map] : myMap)
    {
      for(auto& [capital , weather] : map)
      {
        if(capital == "xyz")
          weather = 20;
      }
    }

another way

 typedef map<string,int> innermap;
 std::map< std::string, innermap > myMap;

 for(auto iterOuter = myMap.begin(); iterOuter != myMap.end(); iterOuter++)
    {
        for(map<string, int>::iterator iterInner = iterOuter->second.begin(); iterInner  != iterOuter->second.end(); iterInner++)
        {
            // do here what you want
        }
    }
Villance
  • 41
  • 1
  • 9
  • if the map is defined as below typedef map innermap; map outermap .. how to assign, access and loop through the same. – ann May 18 '21 at 09:13
  • do you mean `map outermap` . you can access and assign in same way. – Villance May 18 '21 at 09:32
  • thanks but how to access and how to loop through the same typedef map mp map outermap – ann May 18 '21 at 09:37
  • map ::iterator it map ::iterator inner_it for(it =mp.begin();it!=mp.end();it++)--- is throwing error – ann May 18 '21 at 09:37
  • you can user iter like this for(auto iterOuter = myMap.begin(); iterOuter != myMap.end(); iterOuter++) { for(map::iterator iter = iterOuter->second.begin(); iter != iterOuter->second.end(); iter++) { // do here what you want } } – Villance May 18 '21 at 10:02