【发布时间】:2011-04-08 01:44:47
【问题描述】:
如何将两个 STL 映射合并为一个?它们都具有相同的键和值类型 (map<string, string>)。如果键重叠,我想优先选择其中一张地图。
【问题讨论】:
如何将两个 STL 映射合并为一个?它们都具有相同的键和值类型 (map<string, string>)。如果键重叠,我想优先选择其中一张地图。
【问题讨论】:
假设你想保留mapA中的元素,并合并mapB中mapA中没有key的元素:
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
【讨论】:
value_comp() 排序的特殊情况下,它可以实现为 O(n (1 + log(m/(1+n))) + log(m)),但是标准没有强制要求。)
如John Perry's answer 中所述,由于C++17 std::map 提供了merge() 成员函数。 merge() 函数基于使用 insert() 为目标映射生成与 jkerian's solution 相同的结果,正如您从以下示例中看到的那样,我从 jkerian 借来的。我刚刚用C++11 和C++17 的一些特性更新了代码(例如using type alias、range-based for loop 和structured binding 和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;
}
输出:
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() 从bar 中删除4:40,因此只有2:20 和3:30 保留在bar 中。
注意:为了简洁起见,我重用了 jkerian 中使用 map<int, int> 的示例,但 merge() 也适用于您的 map<string, string>。
【讨论】:
请注意,从 C++17 开始,有一个用于映射的 merge() 方法。
【讨论】:
根据 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 的“值”会被保留。
【讨论】:
如果你想将条目从一张地图复制到另一张地图,你可以使用std::map的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 的条目。
【讨论】: