Storing std map in map

64,411

Solution 1

Try:

std::map< std::string, std::map<std::string, std::string> > someStorage;

someStorage["Hi"]["This Is Layer Two"] = "Value";

Solution 2

someStorage["key"].insert(std::make_pair("key2", "value2")));

If you still wanted to use insert on the outer map as well, here is one way to do it

std::map<std::string, std::string> inner;
inner.insert(std::make_pair("key2", "value2"));
someStorage.insert(std::make_pair("key", inner));

Solution 3

A map has a insert method that accepts a key/value pair. Your key is of type string, so that's no problem, but your value is not of type pair (which you generate) but of type map. So you either need to store a complete map as your value or you change the initial map definition to accept a pair as value.

Solution 4

//Try this:

std::map< std::string, std::map<std::string, std::string> > myMap;

myMap["key one"]["Key Two"] = "Value";
myMap["Hello"]["my name is"] = "Value";

//To print the map:

for( map<string,map<string,string> >::const_iterator ptr=myMap.begin();ptr!=myMap.end(); ptr++) {
    cout << ptr->first << "\n";
    for( map<string,string>::const_iterator eptr=ptr->second.begin();eptr!=ptr->second.end(); eptr++){
        cout << eptr->first << " " << eptr->second << endl;

    }

}

Solution 5

Also you can use list initialization:

someStorage.insert( std::make_pair("key", std::map<std::string, std::string> {std::make_pair("key2", "value2")}) );
Share:
64,411
Hanut
Author by

Hanut

Updated on May 01, 2020

Comments

  • Hanut
    Hanut about 4 years

    I have to store std::map as value in std::map

    std::map< std::string, std::map<std::string, std::string> > someStorage;
    

    How to insert into second(inner) map? I tried with:

    someStorage.insert( std::make_pair("key", std::make_pair("key2", "value2")) );
    

    But this throws a lot of errors. What's wrong?

  • TToni
    TToni over 13 years
    That alone won't cut it. Where is the map in the value created?
  • Dark Falcon
    Dark Falcon over 13 years
    You do realize that someStorage["key"] does an insert if required, using a default-initialized value? (in other words, an empty map is associated with the key if the key does not exist)
  • Admin
    Admin over 13 years
    That is needlessly EXPENSIVE as it creates a default string then reassigns it to the value passed in. Best approach is how Dark Falcon has done it: stackoverflow.com/questions/4479017/storing-std-map-in-map/… - I think you're getting voted-up these days only because of your accrued points and not the quality of your answers. I wish people would take the time to read/think about your answers.
  • Martin York
    Martin York over 13 years
    I like my answer because it is the easiest to read. Expense is rarely a factor, maintainability is a real cost. This code is the easiest to maintain. PS. Also copying a string is about as expensive as copying a couple of integers (as most std::string implementations uses a copy on write approach and thus the string is not actually copied).
  • Matthieu M.
    Matthieu M. over 13 years
    @Oxsnarder: What is the cost of creating a default string and then assigning a char const* to it ? The default std::string probably performance no memory allocation (if yours does, shoot off your library provider), and then there is std::string& std::string::operator=(char const*), and of course if the string already exists, then you avoid building a temporary std::string that won't get inserted anyway... I think that you're being needlessly snappy these days.
  • Martin York
    Martin York over 13 years
    You should not use make_pair. You are assuming that the implementation uses pair. Use std::map<Key, Value>::value_type it is typedefed for exactly that reason.
  • Dark Falcon
    Dark Falcon over 13 years
    On the contrary: The C++0x standard says: "For a map<Key,T> the key_type is Key and the value_type is pair<const Key,T>." (23.4.1.2)
  • Stuart Golodetz
    Stuart Golodetz over 13 years
    I'm not particularly interested in the fight going on here -- but bear in mind that your answer above is not semantically equivalent to insert in that it will overwrite a value which is already there whereas insert will not. Which is preferable depends on context, of course -- but the original question in this case does seem to ask for insert.
  • Stuart Golodetz
    Stuart Golodetz over 13 years
    @Martin: Indeed -- unlike the case in point, what I said and what you said are semantically equivalent :)
  • Martin York
    Martin York over 13 years
    @Dark Falcon: Yes exactly. Which is why you should use value_type and not make_pair.
  • Stuart Golodetz
    Stuart Golodetz over 13 years
    @Martin: The bit he quoted is in essence a specific guarantee from the standard that the two are equivalent. In other words, make_pair is always guaranteed to work here (and for what it's worth, it's the idiomatic usage when doing an insert in my experience).
  • Martin York
    Martin York over 13 years
    @Stuart Golodetz: @Dark Falcon: Yes. I understand that. But what do you think the type returned by make_pair is? As a hint its not the same as value_type because "key1", "key2", "value2" are not std::strings! You are lucking out on a couple of implicit conversions. By using value_type you are getting the correct type without having to worry about the compiler doing any implicit conversions. In my team (probably company wide): make_pair is removed at code review time. Here value_type is idiomatic (because it is the type stored in the map).
  • Martin York
    Martin York over 13 years
    @Stuart Golodetz: To rephrase: insert() will not change the value if it already exists, while the above code will change the value. (As translated from PhDish into English for the rest of us). :-)
  • Stuart Golodetz
    Stuart Golodetz over 13 years
    @Martin: Touché ;) I guess the tricky bit was "is not semantically equivalent to", which translates to "does not have the same meaning as". Apologies for talking in weird PhD tongues :-)
  • Stuart Golodetz
    Stuart Golodetz over 13 years
    @Martin: I'm aware that there are implicit conversions going on -- they're desirable from my perspective, because code with make_pair can often be more readable. If they're causing you a performance problem (you profiled, I assume), then sure, it's fair enough to use value_type. But otherwise I don't see a major benefit. Suppose your map is std::map<VeryLongKeyTypeName,VeryLongValueTypeName> m;, you'd certainly want to avoid writing m.insert(std::map<VLKTN,VLVTN>::value_type(k,v)); when you could write m.insert(std::make_pair(k,v)); -- the latter's much clearer.
  • Stuart Golodetz
    Stuart Golodetz over 13 years
    I accept that you could use a typedef, but that's extra hassle for what is in most cases little to no benefit. And if your map type depends on template parameters, then you end up having to add typename before std::map<K,V>::value_type each time. You could do typedef typename std::map<K,V>::value_type MapVal; and then m.insert(MapVal(k,v));, sure, but I don't see the real advantage.
  • Martin York
    Martin York over 13 years
    I would have done: typedef std::map<VeryLongKeyTypeName,VeryLongValueTypeName> Storage; Then its m.insert(Storage::value_type(key,value)); Which is much cleaner and more readable. The cost of the implicit conversions is not the point (I am sure the compiler optimizations would make it practically the same). The implicit conversion is problematic as it is not always obvious what is happening (you happen to get lucky in the std::string is very well tested in this regards, any other user defined type I would be much more suspicious of what is happening (and thus need to spend time checking)).
  • Martin York
    Martin York over 13 years
    The problem here is not when you first write it. Because you know how all your code is working. But the problem comes from maintaining the code. If any types are changed (and this happens a lot) the implicit conversions can start causing massive problems. For Example Key1 is change from a std::string into Application::Key1 this type change will cascade through the program. Using the correct type the first time will prevent problems. Using make_pair with all the associated (extra type conversions (there will always be some but try and minimiz)) will require a lot more verification.
  • Stuart Golodetz
    Stuart Golodetz over 13 years
    @Martin: If e.g. VeryLongKeyTypeName was a template parameter, it would end up being typename Storage::value_type(key, value) of course, because value_type would still be a dependent type. (Just deciding how to reply to the rest, bear with me... :))
  • Stuart Golodetz
    Stuart Golodetz over 13 years
    As far as implicit conversions go, it strikes me that the true problem lies with people who allow implicit conversions that they shouldn't. By default, I'd tend to make most single-parameter constructors explicit unless I was specifically intending to allow the implicit conversion. (I'd also aim to avoid unwise conversion operators, e.g. providing operator const char* for a string type.) If only sensible implicit conversions are supported, I don't see why there should be a major problem.
  • Stuart Golodetz
    Stuart Golodetz over 13 years
    I think the bottom line is that I don't think it makes a vast amount of difference -- the value_type way potentially involves an otherwise unneeded typedef, and is a bit more hassle, but makes the types involved more explicit. The make_pair way is a bit more convenient. If used properly, I don't think either should cause real problems. (I have changed key types of maps before, and I've never had a problem with implicit conversions.) YMMV - I guess I wouldn't have a major problem with using value_type if I worked in one of your teams, but I don't think it really buys you very much.
  • Martin York
    Martin York over 13 years
    @Stuart Golodetz: Well though out arguments. Good luck with the viva.
  • Stuart Golodetz
    Stuart Golodetz over 13 years
    @Martin: Removed, sorry -- no offence intended. Was just curious when you said was all.
  • Martin York
    Martin York about 10 years
    @Gracchus: The performance hit was negligible at best with C++03. With C++11 and move semantics its even less relvant. The thing you need to think about now is weather to use std::map or std::unordered_map.
  • Abhay Hegde
    Abhay Hegde almost 8 years
    @DarkFalcon , How would one construct a map consisting of both primitive values and map inside a map, some thing like the below { 'Key1': '1', 'Key2': { 'a' : '2', 'b' : '3', 'c' : { 'd' : '3', 'e' : '1' } } }