在基于范围的循环中删除地图元素

问题描述 投票:0回答:1

我想根据某些条件从地图中删除一些元素:

#include <unordered_map>
#include <ranges>
#include <iostream>

int main() {

    std::unordered_map<int,int> numbers={{1,2},{2,1},{3,2},{4,5}};
    
    auto even = [](auto entry){return entry.second%2==0;};
    for(auto& [key, val] : numbers | std::views::filter(even)){
        numbers.erase(val);
    }

    for( auto& [key, val] : numbers){
        std::cout << key << " " << val << "\n";
    }
}

但似乎我正在使基于范围的循环所需的迭代器无效:

4 5
3 2
1 2

我知道如何使用迭代器明确地做到这一点,但是是否有一种基于范围的简洁明了的方法来删除基于过滤器的元素?

c++ unordered-map std-ranges range-based-loop
1个回答
3
投票

伊特诺亚

我建议你,像下面那样使用 std::erase_if

    std::erase_if(numbers, [](auto entry) {return entry.second % 2 == 0; });

如果你想要范围解决方案,你不需要就地改变,你可以像下面那样做(这段代码只能在 C++23 中编译)

numbers = numbers | std::views::filter(even) | std::ranges::to<decltype(numbers)>();

我很惊讶!,我不确定,但也许下面的代码比上面的正常范围代码性能更好,基于文档

auto temp_numbers = numbers | std::views::filter(even) | std::ranges::to<decltype(numbers)>();

numbers.swap(temp_numbers);

正如您在 operator= 中看到的那样,对于

std::unordered_map
,Move 赋值运算符的复杂性是 linear,但是 move constructor 的复杂性是 constant,而 swap 的复杂性是 constant,所以看起来以获得更好的性能。但我对此没有任何基准。如果有人对此有任何意见,我非常欢迎。

© www.soinside.com 2019 - 2024. All rights reserved.