在map/unordered_map中查找是否有一个key,并且如果有的话,处理其对应的value,常见代码是用find:
map<int, int> some_map{};
int value{};
auto iter = some_map.find(value);
if(iter != some_map.end()){
// do something with iter->second
}
写起来比较繁琐。特别是当这个map是多级的时候,需要不断地判断iter == some_map.end()。还有一种方法是用count:
map<int, int> some_map{};
int value{};
if(some_map.count(value)){
// do something with some_map.at(value)
}
这个虽然简单了,但是在count()和at()的时候,分别都比较/哈希了一轮,相对耗时,在比较/哈希函数比较复杂的时候尤其明显。考虑写个函数,既能表示有没有找到,又能把找到的值返回回来,只需要一轮比较/哈希。很容易联想到用指针,没找到就返回nullptr,找到的话返回value的地址:
template <typename MapType>
auto MapFind(MapType& map, const typename MapType::key_type& key) {
auto iter = map.find(key);
return iter != map.end() ? &iter->second : nullptr;
}
这个函数利用find的方法,只需要比较/哈希一轮,又有count的直接判断是否找到的能力,客户代码变得简单高效了一些:
map<int, int> some_map{};
int value{};
if(auto res = MapFind(some_map, value)){
// do something with *res
}
对于多级map,则还需要一个重载,接收每一级的key,同时在发现当前级别能找到的情况下,继续往下一次递归地调用,否则返回nullptr:
template <typename MapType, typename... KeyTypes>
auto MapFind(MapType& map, const typename MapType::key_type& key,
const KeyTypes&... key_types) {
auto result = MapFind(map, key);
return result ? MapFind(*result, key_types...) : nullptr;
}
由于返回的是map中元素的地址,所以入参map不允许为右值。测试代码:
template <typename... Args>
using mp = std::map<Args...>; // using mp = std::unordered_map<Args...>;
int main() {
mp<int, mp<char, mp<std::string, mp<void*, const char*>>>> map{
{1, {{'c', {{std::string{"string"}, {{nullptr, "char*"}}}}}}} };
const auto& map1 = map;
auto res0 = MapFind(map, 1, 'c', "string", nullptr);
auto res1 = MapFind(map1, 1, 'c', "string", &res0);
auto res2 = MapFind(map, 1, 'c', "string0", nullptr);
auto res3 = MapFind(map, 1, 'd', "string", nullptr);
auto res4 = MapFind(map, 2, 'c', "string", nullptr);
auto res5 = MapFind(map, 1, 'c', "string");
auto res6 = MapFind(map, 1, 'c');
auto res7 = MapFind(map, 1);
std::cout << *res0 << res5->begin()->first << res6->begin()->first
<< res7->begin()->first << std::endl;
std::cout << (*res0)[1] << std::endl;
}