减少map/unordered_map查找过程中比较/哈希的次数且用户代码简洁的方法

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

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值