Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simplest method to check whether unordered_map of unordered_maps contains key

I am using an unordered_map of unordered_maps, such that I can reference an element using the "multi key" syntax:

my_map[k1][k2].

Is there a convenient way to use the same "multi-key" syntax to check whether an element exists before trying to access it? If not, what is the simplest way?

like image 292
user997112 Avatar asked Dec 29 '15 13:12

user997112


People also ask

How do you check if a key is present in unordered_map?

To check for the existence of a particular key in the map, the standard solution is to use the public member function find() of the ordered or the unordered map container, which returns an iterator to the key-value pair if the specified key is found, or iterator to the end of the container if the specified key is not ...

What does an unordered_map return if the key does not exist?

the unordered map will try to default initialize mystruct with the key 'x' and assign to my struct. if u wanna avoid this, use . at(key) if it doesn't exist it will throw an out_of_range exception , which you can catch it and handle.

Can unordered map have pair as key?

Unordered Map does not contain a hash function for a pair like it has for int, string, etc, So if we want to hash a pair then we have to explicitly provide it with a hash function that can hash a pair. unordered_map can takes upto 5 arguments: Key : Type of key values. Value : Type of value to be stored against the key.


5 Answers

If your intention is to test for the existence of the key, I would not use

my_map[k1][k2]

because operator[] will default construct a new value for that key if it does not already exist.

Rather I would prefer to use std::unordered_map::find. So if you are certain the first key exists, but not the second you could do

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

If you would like to make a function that checks for the existence of both keys, then you could write something like

//------------------------------------------------------------------------------
/// \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;
}
like image 77
Cory Kramer Avatar answered Oct 18 '22 20:10

Cory Kramer


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

will work for every single-valued associative container.

contains(my_map, k1, k2) is true if there is an element k1 which contains k2.

like image 26
Yakk - Adam Nevraumont Avatar answered Oct 18 '22 21:10

Yakk - Adam Nevraumont


In C++20, you can use the contains method (added to all associative containers if I am not mistaken):

if (my_map.contains(k1) && my_map[k1].contains(k2))
{
    // do something with my_map[k1][k2]
}
like image 4
pooya13 Avatar answered Oct 18 '22 21:10

pooya13


You might also use count (http://www.cplusplus.com/reference/unordered_map/unordered_map/count/ )

which will return 0 if key not exist

like image 3
Hui Liu Avatar answered Oct 18 '22 21:10

Hui Liu


Something like this? (for the mutable case)

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

called like so:

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
}

... or there's the more python-like way...

try {
  auto& v = my_map.at(k1).at(k2);
  // use v
}
catch(const std::out_of_range & e) {
  // didn't find it
}
like image 1
Richard Hodges Avatar answered Oct 18 '22 19:10

Richard Hodges