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;
}
Then when this is used intention is clear and simple.
