C++20 ranges

理论介绍

  1. 什么是 ranges?

    • ranges 是 C++20 引入的一个新模块,提供了一组强大的数据处理工具。
    • ranges 建立在迭代器和算法的基础之上,提供了一种更加优雅和高效的数据处理方式。
  2. ranges 的核心概念

    • range: 表示一个元素序列,可以是容器、迭代器区间,甚至是无限序列
    • view: 是 ranges 的核心概念,表示一个惰性求值的 range。
    • 算法: ranges 提供了一系列算法,如 filtertransformtakedrop 等,用于处理 ranges。
  3. ranges 的特点

    • 惰性求值: ranges 中的操作都是惰性求值的,只有在需要结果时才会执行计算。这可以避免不必要的计算,提高性能。对于某些中间结果,例如在循环中使用的元素,ranges 会自动进行缓存,避免重复计算。这在某些场景下可以提高性能。(简单理解:不再是传统一次性全部求值,而是通过迭代器移动,移动一次求一次)
    • 链式调用: views 之间可以进行链式调用,实现复杂的数据处理逻辑。比如 my_range | views::filter(pred) | views::transform(f) | views::take(n) 等。这样可以方便地组合多个操作。
    • 自定义 views: 用户可以自定义自己的 views,扩展 ranges 的功能。用户也可以自定义自己的 views。只需实现 begin()、end() 等迭代器相关的成员函数即可。这为扩展 ranges 功能提供了灵活性。
    • 性能优化: ranges 充分利用 C++20 的新特性,如 move semantics 和 NRVO 等,实现零开销抽象。
    • 并行计算支持: ranges 提供了与 std::execution 兼容的并行计算支持。
  4. ranges 的常用算法

    • std::views::all
      这是一个适配器,它将任何可迭代对象转换为一个视图,保持原始元素顺序。
      std::views::filter
      这个适配器根据给定的谓词过滤范围中的元素,产生一个新的视图。
      std::views::transform
      这个适配器将给定的范围中的每个元素应用指定的转换函数,产生一个新的视图。
      std::views::take
      这个适配器从给定范围中取出前n个元素,产生一个新的视图。
      std::views::take_while
      这个适配器从给定范围中取出满足某个条件的元素,直到遇到第一个不满足条件的元素为止。
      std::views::drop
      这个适配器丢弃给定范围开头的n个元素,产生一个新的视图。
      std::views::drop_while
      这个适配器丢弃给定范围开头满足某个条件的元素,直到遇到第一个不满足条件的元素为止。
      std::views::join
      这个适配器将嵌套的范围连接成一个扁平的范围。
      std::views::lazy_split
      这个适配器将给定范围按指定的分隔符拆分成子范围,但不会立即执行拆分操作。
      std::views::split
      这个适配器将给定范围按指定的分隔符拆分成子范围,立即执行拆分操作。
      std::views::common
      这个适配器将一个不同类型的句柄和范围转换为一个公共范围。
      std::views::reverse
      这个适配器创建一个反向遍历给定范围的新视图。
      std::views::as_const
      这个适配器创建一个视图,该视图中的元素具有const属性。
      std::views::elements
      这个适配器从嵌套范围中提取特定元素,产生一个新的视图。
      std::views::enumerate
      这个适配器将给定范围与它的索引一起产生一个新的视图。
      std::views::zip
      这个适配器将多个范围合并成一个元组范围。
      std::views::zip_transform
      这个适配器将多个范围合并并应用一个转换函数,产生一个新的视图。
      std::views::adjacent
      这个适配器创建一个新视图,其中包含给定范围中相邻元素的对。
      std::views::adjacent_transform
      这个适配器创建一个新视图,其中包含给定范围中相邻元素的转换结果。
      std::views::join_with
      这个适配器将嵌套的范围连接成一个扁平的范围,使用指定的分隔符。

  5. ranges 的应用场景

    • 数据处理和分析
    • 机器学习和信号处理
    • 流式编程和并行计算

使用

命名空间别名:
namespace std { namespace views = ranges::views; }
std::views命名空间别名是std::ranges::views的简写形式。

包含的头文件:
<ranges>头文件包含了一些其他头文件,如<compare>、<initializer_list>和<iterator>。

 实践

比较

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

int main() {
    std::vector<int> numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

    // 使用 range-based for 循环遍历
    int target = 3;
    for (int count = 0; int num : numbers) {
        if (num % 2 == 0) {
            std::cout << num << " ";
            if (++count > target) break;
        }
    }
    std::cout << std::endl; // 输出: 2 4 6 8

    using namespace std::ranges::views;
    for (int data : numbers | filter([](int n){return n %2 == 0;}) | take(3) )
    {
       std::cout << data;
    }
    std::cout << std::endl;  //输出:246
   
    // 使用视图过滤奇数
    std::vector<int> odd_numbers;
    std::ranges::copy(numbers | std::views::filter([](int n) { return n % 2 != 0; } ),std::back_inserter(odd_numbers));
    for (int num : odd_numbers) {
        std::cout << num << " ";
    }
    std::cout << std::endl; // 输出: 1 3 5 7 9

    // 使用算法查找最大值
    int max_value = *std::ranges::max_element(numbers);
    std::cout << "最大值: " << max_value << std::endl; // 输出: 10
     
    //排序
    //传统  std::sort(odd_numbers.begin(), odd_numbers.end());
   
    std::ranges::sort(odd_numbers, std::greater{});
    for (int num : odd_numbers) {
        std::cout << num << " "; //9 7 5 3 1
     }
    return 0;
}

使用zip来快速生成map 

  //使用zip来快速生成map 
 std::vector<int> numbers = { 1, 2, 3, 4, 5 };
 std::vector<std::string> names = { "Alice", "Bob", "Charlie", "David", "Eve" };
 std::vector<double> scores = { 90.5, 85.2, 92.1, 88.7, 93.0 };
 auto zipped_view = std::views::zip(numbers, names, scores);
 for (const auto& [number, name, score] : zipped_view) {
     std::cout << "Number: " << number << ", Name: " << name << ", Score: " << score << std::endl;
 }

zipped_view类型:
std::ranges::zip_view<
  std::vector<int>&,
  std::vector<std::string>&,
  std::vector<double>& >
输出:
        Number: 1, Name: Alice, Score: 90.5
        Number: 2, Name: Bob, Score: 85.2
        Number: 3, Name: Charlie, Score: 92.1
        Number: 4, Name: David, Score: 88.7
        Number: 5, Name: Eve, Score: 93

 总结:<ranges>头文件为C++20引入了一个强大的范围编程框架,提供了丰富的概念、视图和适配器,使得代码更加简洁、表达力强和可组合。这极大地增强了C++标准库在处理序列数据方面的能力。目前还是草案阶段,许多编译器不支持

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值