81

如何将两个 STL 映射合并为一个?它们都具有相同的键和值类型 ( map<string, string>)。如果键有重叠,我想优先选择其中一张地图。

4

5 回答 5

143

假设您要保留 中的元素mapA,并合并mapB其中没有键的元素mapA

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

会做你想做的,我想。

(编辑:如果您使用的是 C++17 或更高版本,请考虑以下答案:https ://stackoverflow.com/a/56594603/118150 )

工作示例:

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

输出:

:!./insert
1:11 2:12 3:13
2:20 3:30 4:40
1:11 2:12 3:13 4:40
于 2010-09-03T21:50:53.837 回答
37

如果要将条目从一个映射复制到另一个映射,可以使用std::map's insert

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

但请注意,insert如果元素的键已经在 targetMap 中,则不会更新元素;这些项目将保持原样。要覆盖元素,您必须显式复制,例如:

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

如果您不介意在 中丢失数据sourceMap,另一种实现复制和覆盖的方法是insert将目标转换为源和std::swap结果:

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

交换后,sourceMap将包含targetMap' 的旧数据,targetMap并将是两个映射的合并,优先于sourceMap' 条目。

于 2014-03-06T09:57:44.950 回答
18

请注意,从 C++17 开始,有merge()一种用于映射的方法。

于 2018-03-31T06:28:05.123 回答
17

C++17

正如约翰佩里的回答中提到的,因为C++17 std::map提供了一个merge()成员函数。该函数为目标地图生成与基于 using的 jkerian 解决方案merge()相同的结果,正如您从以下示例中看到的那样,我从 jkerian 借来了该示例。我刚刚用一些C++11和 C++17 特性更新了代码(例如类型别名、基于范围的带结构化绑定的 for 循环列表初始化):insert()using

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

输出:

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

如您所见,当键重叠时,merge()也会优先考虑目标映射。foo如果你想反其道而行之,那么你必须调用bar.merge(foo);.

insert()但是,使用和merge()处理源映射之间存在差异。这些insert()函数将新条目添加到目标映射,同时merge()从源映射移动条目。这意味着对于上面的示例,insert()它不会改变bar,而是从,merge()中删除,因此只有和保留在 中。4:40bar2:203:30bar

map<int, int>注意:为了简洁起见,我重用了 jkerian 中的示例,但merge()也适用于您的map<string, string>.

Coliru 上的代码

于 2019-06-14T08:46:30.177 回答
3

根据 ISO/IEC 14882:2003,第 23.1.2 节,表 69,表达式 a.insert(i,j):

pre: i,j 不是 a 的迭代器。插入范围 [i, j) 中的每个元素当且仅当在具有唯一键的容器中不存在具有与该元素的键等效的键的元素;

由于该 std::map 必须遵循此限制,因此如果您想优先考虑一个映射中的“值”而不是另一个映射,则应将其插入其中。例如,

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

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

因此,如果 goodKeys 和 betterKeys 中存在任何等效键,则将保留 BetterKeys 的“值”。

于 2015-03-30T17:15:01.947 回答