【问题标题】:Simplest method to check whether unordered_map of unordered_maps contains key检查 unordered_maps 的 unordered_map 是否包含键的最简单方法
【发布时间】:2015-12-29 13:49:13
【问题描述】:

我正在使用 unordered_maps 的 unordered_map,这样我就可以使用“多键”语法来引用元素:

my_map[k1][k2]

有没有一种方便的方法可以在尝试访问之前使用相同的“多键”语法来检查元素是否存在?如果没有,最简单的方法是什么?

【问题讨论】:

标签: c++ c++11 unordered-map


【解决方案1】:

如果您的意图是测试密钥是否存在,我不会使用

my_map[k1][k2]

因为operator[] 将默认为该键构造一个新值(如果它尚不存在)。

我更喜欢使用std::unordered_map::find。因此,如果您确定第一个键存在,而不是第二个,则可以这样做

if (my_map[k1].find(k2) != my_map[k1].end())
{
    // k2 exists in unordered_map for key k1
}

如果您想创建一个函数来检查 两个 键是否存在,那么您可以编写类似

//------------------------------------------------------------------------------
/// \brief Determines a nested map contains two keys (the outer containing the inner)
/// \param[in] data Outer-most map
/// \param[in] a    Key used to find the inner map
/// \param[in] b    Key used to find the value within the inner map
/// \return True if both keys exist, false otherwise
//------------------------------------------------------------------------------
template <class key_t, class value_t>
bool nested_key_exists(std::unordered_map<key_t, std::unordered_map<key_t, value_t>> const& data, key_t const a, key_t const b)
{
    auto itInner = data.find(a);
    if (itInner != data.end())
    {
        return itInner->second.find(b) != itInner->second.end();
    }
    return false;
}

【讨论】:

  • 如果您不确定k1 是否存在,您需要使用两次find - 一次检查k1,一次检查k2。跨度>
  • @zmb 我想这就是我需要的。
  • @user997112 在这种情况下,您可以使用答案下部的nested_key_exists 函数。如果两个键都存在,它将返回true,否则返回false
  • 不清楚是否会缓存值 my_map[k1],因此两次查找可能会很昂贵
  • @Slava 好点,如果这是一个问题,从my_map[k1] 检索到的内部映射可以存储在一个临时变量中,以避免进行两次查找。
【解决方案2】:
template<class M>
bool contains(M const&){return true;}
template<class M, class K, class...Ks>
bool contains(M const&m, K const&k, Ks const&...ks){
  auto it=m.find(k);
  if (it==m.end()) return false;
  return contains(it->second, ks...);
}

适用于每个单值关联容器。

如果存在包含k2 的元素k1,则contains(my_map, k1, k2) 为真。

【讨论】:

    【解决方案3】:

    你也可以使用 count (http://www.cplusplus.com/reference/unordered_map/unordered_map/count/)

    如果key不存在则返回0

    【讨论】:

      【解决方案4】:

      在 C++20 中,您可以使用 contains 方法(如果我没记错的话,添加到所有关联容器中):

      if (my_map.contains(k1) && my_map[k1].contains(k2))
      {
          // do something with my_map[k1][k2]
      }
      

      【讨论】:

      • 这种方法的缺点是k1 搜索会执行两次。更好的解决方案是对单个 k1 搜索的结果执行 k2 搜索。
      【解决方案5】:

      这样的? (对于可变情况)

      using inner_map = std::map<key_type, value_type>;
      using outer_map = std::map<key_type, inner_map>
      
      boost::optional<value_type&> 
      element_for_keys(outer_map& map, const key_type& k1, const key_type& k2)
      {
        auto it_outer = map.find(k1);
        if (it_outer = map.end())
          return {};
        auto &map2 = it_outer->second;
        auto it_inner = map2.find(k2);
        if (it_inner == map2.end())
          return {};
      
        return { it_inner->second };
      }
      

      这样称呼:

      auto op_value = element_for_keys(my_map, kv1, kv2);
      if (op_value) {
        // use op_value.value()
      }
      else {
        // handle case where it does not exist
      }
      

      ...或者还有更类似于python的方式...

      try {
        auto& v = my_map.at(k1).at(k2);
        // use v
      }
      catch(const std::out_of_range & e) {
        // didn't find it
      }
      

      【讨论】:

        【解决方案6】:

        我不相信要检查多键语法,但最简单的方法是使用find 方法。您可以编写一个简单的函数将其应用于unordered_mapunordered_maps

        reference

        【讨论】:

          【解决方案7】:

          另一种方法是使用std::pair作为key,将两级哈希表转化为一级哈希表,好处:

          • 更简单的代码和结构
          • 可能比两级哈希表更快(我们调用更少的哈希函数,获得更紧凑的内存布局以对缓存更友好)

          缺点:我们有一些键冗余,因此对于具有许多重复的大键来说,这将是一个糟糕的选择,但这种情况不会太常见,所以这里的策略仍然有用。

          std::unordered_map<std::pair<int, int>, int> map;
          

          然后检查是否存在:

          使用查找并与结束迭代器进行比较

          map.find(std::make_pair(k0, k1)) != map.end()
          

          带有计数功能(注意不要与 unordered_multimap 一起使用)

          map.count(std::make_pair(k0, k1)) != 0
          

          或 C++20 包含:

          map.contains(std::make_pair(k0, k1))
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2021-11-25
            • 2010-11-19
            • 2012-12-21
            • 2022-09-24
            • 1970-01-01
            • 1970-01-01
            • 2012-01-04
            相关资源
            最近更新 更多