Самый простой способ проверить, содержит ли неупорядоченная карта неупорядоченных карт ключ


Я использую unordered_map из unordered_map, так что я могу ссылаться на элемент, используя синтаксис "multi key":

my_map[k1][k2].

Есть ли удобный способ использовать тот же синтаксис "мульти-ключа", чтобы проверить, существует ли элемент, прежде чем пытаться получить к нему доступ? Если нет, то какой самый простой способ?

5 21

5 ответов:

Если ваше намерение состоит в том, чтобы проверить наличие ключа, я бы не использовал

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;
}
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...);
}

Будет работать для каждого однозначного ассоциативного контейнера.

contains(my_map, k1, k2) истинно, если существует элемент k1, который содержит k2.

Что-то вроде этого? (для изменяемого случая)

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
}

... или есть более питоноподобный способ...

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

Я не верю, что существует синтаксис с несколькими ключами для проверки, но самый простой способ-использовать метод find. Вы можете написать простую функцию, чтобы применить ее к unordered_map из unordered_maps

Ссылка

Вы также можете использовать count (http://www.cplusplus.com/reference/unordered_map/unordered_map/count/ )

Который вернет 0, если ключ не существует