Home > Software engineering >  How to use the map::find() method for a nested map?
How to use the map::find() method for a nested map?

Time:12-04

I have a map<int, map<int,int>> mymap;

How do I use the find() method for nested maps like this?

If I have map<int,int> mymap, mymap.find(key) it gives a result. But what about nested maps for more than 1 key?

CodePudding user response:

mymap.find() will search for the 1st key and return an iterator to a std::pair containing that key's associated value, which is a std::map.

Then find() on that std::map will search for the second key, returning an iterator to a std::pair containing its associated value, which is an int.

For example:

map<int, map<int,int>> mymap;
auto it1 = mymap.find(key1);
if (it1 != mymap.end()) {
    auto it2 = it1->second.find(key2);
    if (it2 != it1->second.end()) {
        // use it2->second as needed...
    }
}

CodePudding user response:

Also note that there is std::map::at.

It throws std::out_of_range if a matching key doesn't exists, but the usage in your case is simple.

auto value = mymap.at(key1).at(key2);

If you are not sure keys exists you can catch this exception or go with approach in Remy's answer.

CodePudding user response:

After

auto entry = mymap.find(key);

you discover that entry is an iterator to a std::pair containing the (const!) key and the value, the latter in your case is yet another map, so:

auto subEntry = entry->second.find(subKey)

(Provided, of course, entry != mymap.end()!)

CodePudding user response:

It is a good practice is to provide a tool to handle such cases.

So solution provided by Remy should take a form of helper function or universal template:

template<typename T, typename Key>
auto optional_at(T& x, Key&& key)
    -> std::optional<typename T::mapped_type>
{
    auto it = x.find(std::forward<Key>(key));
    if (it == x.end()) 
        return {};
    return it->second;
}

template<typename T, typename Key, typename ...Keys>
auto optional_at(T& x, Key&& key, Keys&&...keys)
    -> decltype(optional_at(x[key], std::forward<Keys>(keys)...))
{
    auto it = x.find(std::forward<Key>(key));
    if (it != x.end()) 
        return optional_at(it->second, std::forward<Keys>(keys)...);
    return {};
}

//---------------------
int main()
{
    std::map<int, std::map<int, std::string>> m{
        {1, {{1, "one-one"}}},
        {2, {{1, "two-one"}, {2, "two-two"}}}
    };
    
    ...
    print(std::cout, optional_at(m, 1, 2)) << '\n';
    print(std::cout, optional_at(m, 2, 1)) << '\n';
    print(std::cout, optional_at(m, 2, 2)) << '\n';
    ...

    return 0;
}

Live demo

Then when this is used intention is clear and simple.

  • Related