【问题标题】:Intersection of two std::unordered_map两个 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 为键的键值对不会出现在输出中吗?

标签: c++ unordered-map set-intersection


【解决方案1】:

您可以使用std::set_intersection 填充一个新容器,其中包含两个映射中都存在的keyvalue 对。 set_intersection 需要对范围进行排序(这正是您不会从 unordered_map 得到的)所以要么用 map 替换 unordered_maps 或创建临时的 maps (或临时的 @987654330 @s) 在使用 set_intersection 之前。

如果您经常需要交叉路口,我建议您将原来的 unordered_maps 替换为已订购的 maps 以提高效率:

#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_maps 并且不必创建临时的sets 或maps,您可以将上面的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);
      }
    

    将制作 的映射,其中 对在 mp1 和 mp2 中。

    或者更快

    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 第二个版本需要订购maps。这可能值得一提。
    【解决方案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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-04-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-07
      • 2012-05-23
      • 2022-01-13
      相关资源
      最近更新 更多