3

How can I concatenate the following two maps?

map<string, map<string,string>> map1;
map<string, map<string,string>> map2;

I just want to add map2 to map1 and keep all elements already in map1, i.e., add map2 at the end of map1. I've tried map1.insert(map2.begin(), map2.end()), but it does not work since it overwrites old elements in map1.

honk
  • 9,137
  • 11
  • 75
  • 83
Niklas
  • 149
  • 3
  • 8

6 Answers6

6

If you just want to merge them but in case of collisions keep the elements from map1, then just reverse the maps:

std::swap(map1, map2);
map1.insert(map2.begin(), map2.end());

This of course assumes that after the merge, you're only interested in the result and lo longer in the old collections.

MSalters
  • 173,980
  • 10
  • 155
  • 350
4

map<> can contain only one value for one key. try using multimap<>, for example.

nothrow
  • 15,882
  • 9
  • 57
  • 104
1

The question contradicts with the concept of a map. If you insert a value in a map, you expect it to be at 'the proper place', depending on it's key. This implies there is only one entry for each key.

Instead, you could use a vector< pair< mymap::key, myamap::value > > and fill it with the entries of the first resp. the second map.

map< string, int > map1, map2;
... fill the maps
vector< pair<string, int> > concatted;
concatted.insert( map1.begin(), map1.end() );
concatted.insert( map2.begin(), map2.end() );
xtofl
  • 40,723
  • 12
  • 105
  • 192
  • But doesn't this create two different map i.e. a list containing map[0], map[1]... All I want to do is append maps to another map in a for loop. – Niklas Jun 10 '10 at 07:27
  • @Niklas: that's the point: you cannot append two maps. You can create the 'union', but double entries will get lost. – xtofl Jun 10 '10 at 07:43
  • The `insert()` method requires a `positon` where to insert the range as the first parameter: `... concatted.insert( concatted.begin(), map1.begin(), map1.end() ); ... ` – Khamyl Jun 09 '21 at 09:26
1

Do it with a simple for-loop: (althrough i like to use stl algorithms where plausible):

for(std::map<...>::const_iterator it = map2.begin(), it_end = map2.end(); it != it_end; ++it)
   map1.insert(*it);

Any element whose key already is in map1 won't be overwritten as map::insert doesn't overwrite.

Viktor Sehr
  • 12,825
  • 5
  • 58
  • 90
1

If a map is not too big, do the opposite:

map2.insert(map1.begin(), map1.end());
map1 = map2;

This will overwrite duplicate values in map2, but will keep the ones in map1 (I understand this is what you wanted).

Alex B
  • 82,554
  • 44
  • 203
  • 280
0

Since C++17 std::map provides a merge() member function, so you can simply call map1.merge(map2);. Please note, that a map is sorted by its keys, so that elements will not necessarily be appended at the end. Also, because the keys in a map are unique, not all elements from map2 might be inserted into map1. Full example:

int main() {
    std::map<std::string, std::map<std::string, std::string>> map1{
        {"a", {{"b", "b"}}}, {"b", {{"c", "c"}}}
    };

    std::map<std::string, std::map<std::string, std::string>> map2{
        {"b", {{"x", "x"}}}, {"c", {{"y", "y"}}}
    };

    map1.merge(map2);  // C++17

    std::cout << "map1:" << std::endl;
    for (auto const &kv : map1)
        std::cout << kv.first << ": " << kv.second.begin()->first << std::endl;

    std::cout << std::endl << "map2:" << std::endl;
    for (auto const &kv : map2)
        std::cout << kv.first << ": " << kv.second.begin()->first << std::endl;

    return 0;
}

Output:

map1:
a: b
b: c
c: y

map2:
b: x

As you can see, merge() does not overwrite existing elements in the target map map1 when keys overlap. If you want to to give priority to elements from map2, then you have to call map2.merge(map1);. As you can also see, merge() moves entries over from the source map. Elements that cannot be merged remain in map2.

Code on Coliru

honk
  • 9,137
  • 11
  • 75
  • 83