开发者

How can I merge two STL maps?

开发者 https://www.devze.com 2023-01-14 15:29 出处:网络
How can I merge two STL maps into one? They both have the same key and value types (map<string, string>). If the开发者_Go百科re is an overlap of the keys, I would like to give preference to one

How can I merge two STL maps into one? They both have the same key and value types (map<string, string>). If the开发者_Go百科re is an overlap of the keys, I would like to give preference to one of the maps.


Assuming you want to preserve the elements in mapA, and merge elements in mapB for which there is no key in mapA:

mapA.insert(mapB.begin(), mapB.end())

will do what you want, I think.

(EDIT: If you are using C++17 or newer, consider this answer: https://stackoverflow.com/a/56594603/118150)

Working example:

#include <iostream>
#include <map>

void printIt(std::map<int,int> m) {
    for(std::map<int,int>::iterator it=m.begin();it!=m.end();++it)
        std::cout << it->first<<":"<<it->second<<" ";
    std::cout << "\n";
}

int main() {
    std::map<int,int> foo,bar;
    foo[1] = 11; foo[2] = 12; foo[3] = 13;
    bar[2] = 20; bar[3] = 30; bar[4] = 40;
    printIt(foo);
    printIt(bar);
    foo.insert(bar.begin(),bar.end());
    printIt(foo);
    return 0;
}

output:

:!./insert
1:11 2:12 3:13
2:20 3:30 4:40
1:11 2:12 3:13 4:40


If you want to copy entries from one map to another, you can use std::map's insert:

targetMap.insert(sourceMap.begin(), sourceMap.end());

But note that insert does not update elements if their key is already in targetMap; those items will be left as-is. To overwrite elements, you will have to copy explicitly, e.g.:

for(auto& it : sourceMap)
{
    targetMap[it.first] = it.second;
}

If you don't mind losing the data in sourceMap, another way to achieve a copy-and-overwrite is to insert the target into the source and std::swap the results:

sourceMap.insert(targetMap.begin(), targetMap.end());
std::swap(sourceMap, targetMap);

After swapping, sourceMap will contain targetMap's old data, and targetMap will be a merge of the two maps, with preference for sourceMap's entries.


C++17

As mentioned in John Perry's answer, since C++17 std::map provides a merge() member function. The merge() function produces the same result for the target map as jkerian's solution based on using insert(), as you can see from the following example, which I borrowed from jkerian. I just updated the code with some C++11 and C++17 features (such as using type alias, range-based for loop with structured binding, and list initialization):

using mymap = std::map<int, int>;

void printIt(const mymap& m) {
    for (auto const &[k, v] : m)
        std::cout << k << ":" << v << " ";
    std::cout << std::endl;
}

int main() {
    mymap foo{ {1, 11}, {2, 12}, {3, 13} };
    mymap bar{ {2, 20}, {3, 30}, {4, 40} };
    printIt(foo);
    printIt(bar);
    foo.merge(bar);
    printIt(foo);
    return 0;
}

Output:

1:11 2:12 3:13
2:20 3:30 4:40
1:11 2:12 3:13 4:40

As you can see, merge() also gives priority to the target map foo when keys overlap. If you want to have it the other way round, then you have to call bar.merge(foo);.

However, there is a difference between using insert() and merge() regarding what happens to the source map. The insert() functions adds new entries to the target map, while merge() moves entries over from the source map. This means for the example above, that insert() does not alter bar, but merge() removes 4:40 from bar, so that only 2:20 and 3:30 remain in bar.

Note: I reused the example from jkerian which uses map<int, int> for the sake of brevity, but merge() also works for your map<string, string>.

Code on Coliru


Notice that, since C++17, there is a merge() method for maps.


According to ISO/IEC 14882:2003, section 23.1.2, Table 69, expression a.insert(i,j):

pre: i,j are not iterators into a. inserts each element from the range [i, j) if and only if there is no element with key equivalent to the key of that element in containers with unique keys;

Since that std::map must follow this restriction, if you'd like to give preference to "values" from one map over another you should insert into it. For example,

std::map<int, int> goodKeys;
std::map<int, int> betterKeys;

betterKeys.insert(goodKeys.begin(), goodKeys.end());

So if there are any equivalent keys in goodKeys and betterKeys, "values" of the betterKeys will be preserved.

0

精彩评论

暂无评论...
验证码 换一张
取 消