C++ 如何合并两个 STL 映射?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3639741/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I merge two STL maps?
提问by JonF
How can I merge two STL maps into one? They both have the same key and value types (map<string, string>
). If there is an overlap of the keys, I would like to give preference to one of the maps.
如何将两个 STL 映射合并为一个?它们都具有相同的键和值类型 ( map<string, string>
)。如果键有重叠,我想优先选择其中一张地图。
回答by jkerian
Assuming you want to preserve the elements in mapA
, and merge elements in mapB
for which there is no key in mapA
:
假设您要保留 中的元素mapA
,并合并mapB
没有 in 键的元素mapA
:
mapA.insert(mapB.begin(), mapB.end())
will do what you want, I think.
会做你想做的,我想。
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
回答by kiwibonga
If you want to copy entries from one map to another, you can use std::map
's insert
:
如果要将条目从一张地图复制到另一张地图,可以使用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.:
但请注意,insert
如果元素的键已经在 targetMap 中,则不会更新元素;这些项目将保持原样。要覆盖元素,您必须显式复制,例如:
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
将目标放入源和std::swap
结果中:
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.
交换后,sourceMap
将包含targetMap
的旧数据,targetMap
并将是两个映射的合并,优先选择sourceMap
的条目。
回答by John Perry
回答by honk
C++17
C++17
As mentioned in John Perry's answer, since C++17std::map
provides a merge()
member function. The merge()
function produces the same result for the target map as jkerian's solutionbased on using insert()
, as you can see from the following example, which I borrowed from jkerian. I just updated the code with some C++11and C++17 features (such as using
type alias, range-based for loopwith structured binding, and list initialization):
正如John Perry's answer 中提到的,因为C++17std::map
提供了一个merge()
成员函数。该merge()
函数为目标地图生成与基于 using 的jkerian 解决方案相同的结果insert()
,正如您从我从 jkerian 借用的以下示例中看到的。我刚刚用一些C++11和 C++17 特性更新了代码(例如using
类型别名、具有结构化绑定的基于范围的 for 循环和列表初始化):
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
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);
.
如您所见,当键重叠时,merge()
也会优先考虑目标地图foo
。如果你想反过来,那么你必须调用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
.
但是,使用insert()
和merge()
关于源映射发生的事情之间存在差异。这些insert()
函数向目标映射添加新条目,同时merge()
从源映射移动条目。这意味着对于上面的示例, thatinsert()
不会改变bar
,而是从 中merge()
删除,因此只有和保留在 中。4:40
bar
2:20
3:30
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>
.
注意:map<int, int>
为了简洁起见,我重用了 jkerian 中的示例,但merge()
也适用于您的map<string, string>
.
回答by Valentine Savchenko
According to ISO/IEC 14882:2003, section 23.1.2, Table 69, expression a.insert(i,j):
根据 ISO/IEC 14882:2003,第 23.1.2 节,表 69,表达式 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;
pre: i,j 不是 a 的迭代器。插入范围 [i, j) 中的每个元素,当且仅当在具有唯一键的容器中没有与该元素的键等效的键的元素;
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 必须遵循此限制,因此如果您希望将一个映射中的“值”优先于另一个映射,则应将其插入其中。例如,
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.
因此,如果 goodKeys 和 betterKeys 中存在任何等效键,则 BetterKeys 的“值”将被保留。