当前位置: 首页 > news >正文

std::ranges::views::take, take_while,std::ranges::take_view,take_while_view

std::ranges::views::take and std::ranges::take_view

 是C++20 引入的范围库中的组件,用于创建包含原范围前 N 个元素的视图。

核心概念

  1. std::ranges::take_view:

    • 一个范围适配器,生成原范围的前 N 个元素的视图

    • 若原范围元素少于 N 个,则取整个范围。

    • 惰性求值:不会立即复制元素,只在遍历时生成。

    • 满足 view 概念(拷贝/移动成本低)。

  2. std::ranges::views::take:

    • 范围适配器闭包对象(Range Adaptor Closure Object),可通过管道操作符 | 链式调用。

    • 生成 take_view,语法更简洁。

使用方式

1. 直接构造 take_view
#include <ranges>
#include <vector>
#include <iostream>

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};
    // 创建包含前 3 个元素的视图
    auto tv = std::ranges::take_view(v, 3);
    
    for (int x : tv) {
        std::cout << x << " ";  // 输出: 1 2 3
    }
}

2. 通过 views::take 适配器
#include <ranges>
#include <iostream>
#include <vector>

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};
    auto tv = v | std::views::take(3);  // 链式调用
    
    for (int x : tv) {
        std::cout << x << " ";  // 输出: 1 2 3
    }
}

典型场景示例

示例 1:处理有限范围
#include <algorithm>
#include <iostream>
#include <ranges>
 
int main()
{
    namespace views = std::views;
    auto print = [](char x){ std::cout << x; };
 
    for (const char nums[]{'1', '2', '3'};
         int n : views::iota(0, 5))
    {
        std::cout << "take(" << n << "): ";
        // safely takes only upto min(n, nums.size()) elements:
        std::ranges::for_each(nums | views::take(n), print);
        std::cout << '\n';
    }
}

Output:

take(0): 
take(1): 1
take(2): 12
take(3): 123
take(4): 123
示例 2:处理无限序列
#include <ranges>
#include <iostream>

int main() {
    // 生成自然数序列 0,1,2,...,取前 5 个
    auto infinite = std::views::iota(0) | std::views::take(5);
    for (int x : infinite) {
        std::cout << x << " ";  // 输出: 0 1 2 3 4
    }
}
示例 3:链式组合适配器
#include <ranges>
#include <vector>
#include <iostream>

int main() {
    std::vector<int> v = {5, 2, 8, 3, 1, 4};
    // 过滤偶数后取前 2 个
    auto result = v 
        | std::views::filter([](int x) { return x % 2 == 0; })
        | std::views::take(2);
    
    for (int x : result) {
        std::cout << x << " ";  // 输出: 2 8
    }
}

注意事项

  1. N 为非负整数:传入负数可能导致未定义行为。

  2. 性能优势:惰性求值避免复制大范围。

  3. 兼容性:可与任何满足 std::ranges::range 的容器或视图组合。

通过 take_view 和 views::take,可以高效处理范围的前 N 个元素,是函数式编程风格的典型工具。

std::ranges::views::take_while and std::ranges::take_while_view

C++20 范围库中用于根据条件截取范围元素的组件。它们会生成一个视图,包含原范围中从起始位置到第一个不满足条件的元素之前的所有元素

核心概念

  1. std::ranges::take_while_view:

    • 根据谓词(Predicate)截取原范围中满足条件的元素,直到遇到第一个不满足条件的元素为止

    • 若所有元素都满足条件,则包含整个范围。

    • 惰性求值:仅在遍历时检查条件,不提前计算。

    • 满足 view 概念(低开销拷贝/移动)。

  2. std::ranges::views::take_while:

    • 范围适配器闭包对象(Range Adaptor Closure Object),可通过管道操作符 | 链式调用。

    • 生成 take_while_view,语法更简洁。

使用方式

1. 直接构造 take_while_view
#include <ranges>
#include <vector>
#include <iostream>

int main() {
    std::vector<int> v = {2, 4, 6, 7, 8, 10};
    // 截取元素,直到遇到第一个奇数(7)
    auto tv = std::ranges::take_while_view(v, [](int x) { return x % 2 == 0; });
    
    for (int x : tv) {
        std::cout << x << " ";  // 输出: 2 4 6
    }
}
2. 通过 views::take_while 适配器
#include <ranges>
#include <iostream>
#include <vector>

int main() {
    std::vector<int> v = {5, 3, 8, 2, 1, 4};
    
    // 修复:将 prev 初始化为首个元素的值
    // 使用引用捕获外部变量(或直接重构逻辑)
    int prev = v.front(); // 假设 v 非空
    auto tv = v | std::views::take_while(
        [&prev](int x)  { // 引用捕获 prev
            bool result = (x >= prev);
            prev = x;
            return result;
        }
    );
    
    for (int x : tv) {
        std::cout << x << " ";  //输出 5
    }
}

典型场景示例

示例 1:
#include <iostream>
#include <ranges>
 
int main()
{
    for (int year : std::views::iota(2020)
                  | std::views::take_while([](int y){ return y < 2026; }))
        std::cout << year << ' ';
    std::cout << '\n';
 
    const char note[]{"Today is yesterday's tomorrow!..."};
    auto not_dot = [](char c){ return c != '.'; };
    for (char x : std::ranges::take_while_view(note, not_dot))
        std::cout << x;
    std::cout << '\n';
}

Output:

2020 2021 2022 2023 2024 2025
Today is yesterday's tomorrow!
示例 2:处理无限序列
#include <ranges>
#include <iostream>

int main() {
    // 生成自然数序列 0,1,2,...,截取直到数值 >=5
    auto infinite = std::views::iota(0)
        | std::views::take_while([](int x) { return x < 5; });
    
    for (int x : infinite) {
        std::cout << x << " ";  // 输出: 0 1 2 3 4
    }
}
示例 3:链式组合适配器
#include <ranges>
#include <vector>
#include <iostream>

int main() {
    std::vector<int> v = {5, 8, 2, 3, 1, 4};
    // 1. 先过滤偶数,再截取直到数值 <5
    auto result = v 
        | std::views::filter([](int x) { return x % 2 == 0; })
        | std::views::take_while([](int x) { return x >= 5; });
    
    for (int x : result) {
        std::cout << x << " ";  // 输出: 8(过滤后为 [8,2,4],但 8 >= 5,2 < 5)
        // 实际输出为 8
        // 更正:filter 后的序列是 [2,8,4],take_while(x>=5) 会检查每个元素:
        //第一个元素 8>=5成立,第二个元素 2 >=5 不成立,则停止,因此结果为8。
    }
}

注意事项

  1. 谓词要求

    • 谓词必须接受范围的元素类型参数并返回 bool

    • 若谓词有状态(如示例 2 中的 prev),需标记为 mutable

  2. 提前终止

    • 一旦遇到不满足条件的元素,立即停止遍历,后续元素不再检查。

    • 与 std::views::filter 不同,take_while 不保留后续满足条件的元素。

  3. 兼容性

    • 适用于任何满足 std::ranges::input_range 的范围。

    • 若范围在遍历过程中被修改,可能导致未定义行为。

  4. 性能

    • 惰性求值避免不必要的计算,但频繁调用谓词可能影响性能。

http://www.dtcms.com/a/61134.html

相关文章:

  • SVT-AV1源码分析build_intra_predictors函数
  • 开源安全测试工具 | 网络安全工具列表
  • 蓝桥与力扣刷题(441 排列硬币)
  • 【Hadoop】
  • sublime text 中添加copilot
  • 【spring】配置类和整合Junit
  • Dubbo、SpringCloud框架学习
  • 批量将 Excel 转换 PDF/Word/CSV以及图片等其它格式
  • OpenHarmony子系统开发 -- 构建系统编码规范与最佳实践
  • 非软件开发项目快速上手:14款管理软件精选
  • Flutter开发避坑指南:高频问题排查与性能调优实战
  • 【互联网性能指标】QPS/TPS/PV/UV/IP/GMV/DAU/MAU/RPS
  • 探秘稀疏注意力:高效计算的新钥匙
  • 自学网络安全(黑客技术)2025年 —90天学习计划
  • 《Android APP 启动流程深度解析》
  • PostgreSQL-01-入门篇-简介
  • 天梯选拔赛赛后补题
  • 一键装数据库脚本3分钟极速部署,传统耗时砍掉95%!
  • 基于STM32的逻辑分析仪
  • MoonSharp 文档二
  • 蓝桥杯FPGA-ds1302驱动
  • 九点标定和十二点标定的区别
  • 【问题记录】如何编译nv_peer_memory模块?依赖OFED的4个目录和2类文件?如何解决没有rdma/peer_mem.h文件?
  • Python 远程抓取服务器日志最后 1000行
  • Vue3 路由的历史记录 如何不允许浏览器前进后退 在函数中使用路由切换组件 路由的重定向
  • 鸿基智启:东土科技为具身智能时代构建确定性底座
  • 英国赫瑞瓦特大学激光雷达领域研究概述2025.3.11
  • 计算机毕业设计:公寓管理系统
  • Ubuntu本地部署Open manus(完全免费可用)
  • 【OpenCV C++】存图,如何以时间命名,“年月日-时分秒“产生唯一的文件名呢?“年月日-时分秒-毫秒“ 自动检查存储目录,若不存在自动创建存图