两个 std::unordered_map 的交集
Posted
技术标签:
【中文标题】两个 std::unordered_map 的交集【英文标题】:Intersection of two std::unordered_map 【发布时间】:2020-06-30 16:58:53 【问题描述】:我有两个 std::unordered_map
std::unordered_map<int, int> mp1;
std::unordered_map<int, int> mp2;
我需要找到键值对的交集并将其存储在表单的另一个映射中。
std::unordered_map<int, int> mp;
我该怎么做??
【问题讨论】:
关于键、值或键值对的交集? 键值对的交集 将该信息添加到问题中,而不是作为评论。此外,如果您展示一个输入和输出示例,将会很有帮助。 std::set_intersection 浮现在脑海中。 在给定某个键 x,mp1[x] 和 mp2[x] 都存在但 mp1[x] != mp2[x] 的情况下,您需要指定交集的含义。在这种情况下,以 x 为键的键值对不会出现在输出中吗? 【参考方案1】:您可以使用std::set_intersection
填充一个新容器,其中包含两个映射中都存在的key
、value
对。 set_intersection
需要对范围进行排序(这正是您不会从 unordered_map
得到的)所以要么用 map
替换 unordered_map
s 或创建临时的 map
s (或临时的 @987654330 @s) 在使用 set_intersection
之前。
如果您经常需要交叉路口,我建议您将原来的 unordered_map
s 替换为已订购的 map
s 以提高效率:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <map>
#include <unordered_map>
#include <vector>
int main()
std::map<int, int> mp1 1,0, 2,0, 3,0;
std::map<int, int> mp2 0,0, 2,0, 3,0;
// this can be unordered unless you plan to use it in an intersection later:
std::unordered_map<int, int> mp;
std::set_intersection(
mp1.begin(), mp1.end(),
mp2.begin(), mp2.end(),
std::inserter(mp, mp.begin())
);
for(auto[key, val] : mp)
std::cout << key << ',' << val << '\n';
可能的输出:
3,0
2,0
如果您想保留unordered_map
s 并且不必创建临时的set
s 或map
s,您可以将上面的set_intersection
替换为手动填充:
const auto& [min, max] = std::minmax(mp1, mp2,
[](auto& a, auto& b)
return a.size() < b.size();
);
for(auto& [key, value] : min) // iterate over the smallest map
auto fi = max.find(key); // find in the bigger map
if(fi != max.end() && fi->second == value)
mp.emplace(key, value); // add the pair if you got a hit
迭代最小映射的原因是将find
操作的数量保持在最低限度。考虑一个地图包含 1 个元素和其他 1000000 个元素的情况。然后,您需要 1 次查找而不是 1000000。
一个更通用的解决方案可能是用它制作一个函数模板:
template<
class Key,
class T,
class Hash = std::hash<Key>,
class KeyEqual = std::equal_to<Key>,
class Allocator = std::allocator< std::pair<const Key, T> >
>
auto unordered_map_intersection(
const std::unordered_map<Key,T,Hash,KeyEqual,Allocator>& mp1,
const std::unordered_map<Key,T,Hash,KeyEqual,Allocator>& mp2)
std::unordered_map<Key,T,Hash,KeyEqual,Allocator> mp;
const auto& [min, max] = std::minmax(mp1, mp2,
[](auto& a, auto& b)
return a.size() < b.size();
);
for(auto& [key, value] : min) // iterate over the smallest map
auto fi = max.find(key); // find in the bigger map
if(fi != max.end() && fi->second == value)
mp.emplace(key, value); // add the pair if you got a hit
return mp;
【讨论】:
【参考方案2】:for(auto it=mp1.begin();it!=mp1.end();it++)
auto it1=mp2.find(it->first);
if(it1==mp2.end())
continue;
if((*it1)==(*it))
mp.insert(*it);
将制作
或者更快
auto it1=mp1.begin();
auto it2=mp2.begin();
while(it1!=mp1.end() && it2!=mp2.end())
if((*it1)==(*it2))
mp.insert(*it1);
it1++;
it2++;
continue;
if((*it1)<(*it2))
it1++;
else
it2++;
【讨论】:
这不如使用std::set_intersection
高效,因为此函数利用了 map 是有序容器这一事实,因此不需要每次都进行查找。
对不起,现在应该更好了
@D.Smirnov 第二个版本需要订购map
s。这可能值得一提。【参考方案3】:
这是使用std :: set
的手动解决方案:
#include <iostream>
#include <set>
#include <unordered_map>
std :: unordered_map <int, int> intersection (std :: unordered_map <int, int> m1, std :: unordered_map <int, int> m2)
std :: set <std :: pair <int, int>> s (m1.begin(), m1.end());
std :: unordered_map <int, int> i;
for (auto p: m2)
if (s.find (p) != s.end())
i.insert (p);
return i;
int main()
std :: unordered_map <int, int> m1 = 2, 3 , 5, 7 , 11, 5 , 6, 7 ;
std :: unordered_map <int, int> m2 = 21, 13 , 2, 3 , 6, 7 , 3, 2 ;
std :: unordered_map <int, int> i = intersection (m1, m2);
for (auto p: i)
std :: cout << p.first << ' ' << p.second << '\n';
return 0;
输出:
6 7
2 3
【讨论】:
以上是关于两个 std::unordered_map 的交集的主要内容,如果未能解决你的问题,请参考以下文章
std::vector 或 std::list 用于 std::unordered_map 存储桶?
std::unordered_map::clear() 做啥?
在 std::map 和 std::unordered_map 之间进行选择 [重复]
如何在 std::tuple 中合并 std::unordered_map?