I have a map<int, map<int,int>> mymap;
How do I use the find()
method for nested map
s like this?
If I have map<int,int> mymap, mymap.find(key)
it gives a result. But what about nested map
s 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.