std::ranges::views::filter

C++20 std::ranges::views::filter 用法详解

std::ranges::views::filter

C++20 引入的视图适配器,用于根据谓词条件惰性过滤范围内的元素。

Defined in header <ranges>

template< ranges::input_range V,

          std::indirect_unary_predicate<ranges::iterator_t<V>> Pred >
    requires ranges::view<V> && std::is_object_v<Pred>
class filter_view

    : public ranges::view_interface<filter_view<V, Pred>>
(1)(since C++20)
namespace views {

    inline constexpr /* unspecified */ filter = /* unspecified */;

}
(2)(since C++20)

Call signature

template< ranges::viewable_range R, class Pred >

    requires /* see below */

constexpr ranges::view auto filter( R&& r, Pred&& pred );
(since C++20)

template< class Pred >
constexpr /* range adaptor closure */ filter( Pred&& pred );

(since C++20)

以下是对其详细说明及示例: 

基本用法

filter 接受一个谓词(返回 bool 的可调用对象),并生成仅包含满足条件元素的视图

示例 1:过滤偶数
#include <iostream>
#include <vector>
#include <ranges>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5, 6};
    auto even = vec | std::ranges::views::filter([](int i) { return i % 2 == 0; });
    
    for (int n : even) {
        std::cout << n << ' '; // 输出:2 4 6
    }
}

动态条件过滤自定义类型

通过捕获变量,可动态调整过滤条件对象为自定义结构体或类。

示例 2:过滤成年人
#include <iostream>
#include <vector>
#include <ranges>
#include <string>

struct Person 
{
    int age;
    std::string name;
};

void foo(int age)
{
    std::vector<Person> people = {{20, "Alice"}, {15, "Bob"}, {25, "Charlie"}};

    auto adults = people | std::ranges::views::filter([age](const Person& p) { 
        return p.age >= age; 
    });

    for (const auto& p : adults) 
    {
        std::cout << p.name << ' '; // 输出:Alice Charlie
    }
}

int main() 
{
    foo(18); 
}

组合视图适配器

通过管道符 | 链式组合多个视图适配器。

示例 3:过滤偶数后平方
auto processed = vec | std::ranges::views::filter([](int i) { return i % 2 == 0; })
                    | std::ranges::views::transform([](int i) { return i * i; });

for (int n : processed) {
    std::cout << n << ' '; // 输出:4 16 36
}
示例 4:过滤非空字符串并转大写
std::vector<std::string> words = {"hello", "", "world", "", "cpp"};
auto non_empty_upper = words 
    | std::ranges::views::filter([](const std::string& s) { return !s.empty(); })
    | std::ranges::views::transform([](std::string s) {
        std::transform(s.begin(), s.end(), s.begin(), ::toupper);
        return s;
    });

for (const auto& s : non_empty_upper) {
    std::cout << s << ' '; // 输出:HELLO WORLD CPP
}

反向迭代

若原始范围支持双向迭代,filter 视图可反向遍历(需注意效率)。

示例 6:反向输出偶数
for (auto it = even.rbegin(); it != even.rend(); ++it) {
    std::cout << *it << ' '; // 输出:6 4 2
}

与 copy_if 的区别

  • filter 视图:惰性求值,不存储结果,适用于流式处理。

  • copy_if 算法:立即执行并将结果保存到容器中。

总结

  • 惰性求值:仅在遍历时计算,节省内存。

  • 链式组合:可与其他视图适配器(如 transformtake)灵活组合。

  • 谓词灵活性:支持 Lambda、函数对象或成员函数。

  • 迭代器依赖:迭代器类别继承自原始范围,可能影响性能。

transfrom和filter之间的问题

#include <iostream>
#include <vector>
#include <algorithm>
#include <ranges>

void test_transform_filter()
{
    std::vector<int> coll{8,15,7,0,9};

    auto vColl = coll | std::views::transform([](auto&& i)
                            {
                                std::cout << "transform " << i << '\n';
                                return -i;})
                      | std::ranges::views::filter([](int i){
                          std::cout << " filter " << i << '\n';
                          return i%3 == 0;
                      });

    for (int val: vColl)
    {
        std::cout << "val: " << val << '\n';
    }
}
void test_filter_transform()
{
    std::vector<int> coll{8,15,7,0,9};

    auto vColl = coll | std::ranges::views::filter([](int i){
                          std::cout << " filter " << i << '\n';
                          return i%3 == 0;
                      })
                      | std::views::transform([](auto&& i){
                                std::cout << "transform " << i << '\n';
                                return -i;});

    for (int val: vColl)
    {
        std::cout << "val: " << val << '\n';
    }
}

int main(void)
{
    test_transform_filter();

    std::cout << "-------------------------\n" << std::endl;

    test_filter_transform();

    return 0;
}

输出:

transform 8
 filter -8
transform 15
 filter -15
transform 15
val: -15
transform 7
 filter -7
transform 0
 filter 0
transform 0
val: 0
transform 9
 filter -9
transform 9
val: -9
-------------------------

 filter 8
 filter 15
transform 15
val: -15
 filter 7
 filter 0
transform 0
val: 0
 filter 9
transform 9
val: -9

从输出结果可以看出来,在transform | filter这种组合情况下,满足filter的item,会被transform两次。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值