C++范围操作(2)

C++范围操作(2)

主要介绍c++23中的范围操作

ranges相关

1、std::ranges::to

在c++20中,想要将结果转成最终的容器,需要手动操作,c++23中提供了常用容器的转换操作

cpp 复制代码
int main() {
	// 转成vector
	std::vector vec = std::views::iota(1, 21)
		| std::views::filter([](int it) { return it % 3 == 0; })
		| std::ranges::to<std::vector>();
	std::cout << endl << "-------------vector-----------------" << endl;
	for (int x : vec) {
		std::cout << x << ", ";
	}


	// 转成list
	std::list list1 = std::views::iota(1, 21)
		| std::views::filter([](int it) { return it % 3 == 0; })
		| std::ranges::to<std::list>();
	std::cout << endl << "-------------list-----------------" << endl;
	for (int x : list1) {
		std::cout << x << ", ";
	}

	// 转成forward_list
	std::forward_list list2 = std::views::iota(1, 21)
		| std::views::filter([](int it) { return it % 3 == 0; })
		| std::ranges::to<std::forward_list>();
	std::cout << endl << "-------------forward_list-----------------" << endl;
	for (int x : list2) {
		std::cout << x << ", ";
	}


	// 转成set
	std::set set = std::views::iota(1, 21)
		| std::views::filter([](int it) { return it % 3 == 0; })
		| std::ranges::to<std::set>();
	std::cout << endl << "-------------set-----------------" << endl;
	for (int x : set) {
		std::cout << x << ", ";
	}

	// 转成map
	std::map map1 = std::views::iota(1, 21)
		| std::views::filter([](int it) { return it % 3 == 0; })
		| std::views::enumerate				// 生成索引
		| std::ranges::to<std::map>();
	std::cout << endl << "-------------map-----------------" << endl;
	for (auto entry : map1) {
		std::cout << "(" << entry.first << "," << entry.second << ") , ";
	}

	// 转成queue
	std::queue que1 = std::views::iota(1, 21)
		| std::views::filter([](int it) { return it % 3 == 0; })
		| std::ranges::to<std::queue>();
	std::cout << endl << "-------------queue-----------------" << endl;
	while (!que1.empty())
	{
		cout << que1.front() << ", ";
		que1.pop();
	}

	// 转成deque
	std::deque que2 = std::views::iota(1, 21)
		| std::views::filter([](int it) { return it % 3 == 0; })
		| std::ranges::to<std::deque>();
	std::cout << endl << "-------------deque-----------------" << endl;
	while (!que2.empty())
	{
		cout << que2.front() << ", ";
		que2.pop_front();
	}

	// 转成priority_queue
	std::priority_queue que3 = std::views::iota(1, 21)
		| std::views::filter([](int it) { return it % 3 == 0; })
		| std::ranges::to<std::priority_queue>();
	std::cout << endl << "-------------priority_queue-----------------" << endl;
	while (!que3.empty())
	{
		cout << que3.top() << ", ";
		que3.pop();
	}

	// 转成stack
	std::stack stk = std::views::iota(1, 21)
		| std::views::filter([](int it) { return it % 3 == 0; })
		| std::ranges::to<std::stack>();
	std::cout << endl << "-------------stack-----------------" << endl;
	while (!stk.empty())
	{
		cout << stk.top() << ", ";
		stk.pop();
	}

	return 0;
}

2、std::ranges::fold_left与std::ranges::fold_right

  • std::ranges::fold_left
    • 左折叠顺序 ‌:操作顺序为 f(f(f(init, x1), x2), ..., xn)
    • 灵活参数‌:支持迭代器对或直接传入范围对象
    • 类型安全 ‌:提供编译时类型检查,比传统 std::accumulate 更安全
  • std::ranges::fold_right、
    • 左折叠顺序 ‌:操作顺序为 f(x1, f(x2, f(..., f(xn, init)...))
    • 灵活参数‌:支持迭代器对或直接传入范围对象
    • 类型安全 ‌:提供编译时类型检查,比传统 std::accumulate 更安全
      c++
cpp 复制代码
int main()
{
	system("chcp 65001");
	auto view = std::views::iota(1, 11)
		| std::views::filter([](int it) { return it > 0; });

	// 加法
	int result1 = std::ranges::fold_left(view, 0, std::plus<int>());
	int result2 = std::ranges::fold_right(view, 0, std::plus<int>());
	std::cout << "result2= " << result2 << endl;
	std::cout << "result2= " << result2 << endl;

	// 减法
	result1 = std::ranges::fold_left(view, 0, std::minus<int>());
	result2 = std::ranges::fold_right(view, 0, std::minus<int>());
	std::cout << "result1= " << result1 << endl;
	std::cout << "result2= " << result2 << endl;

	// 乘法
	result1 = std::ranges::fold_left(view, 1, std::multiplies<int>());
	result2 = std::ranges::fold_right(view, 1, std::multiplies<int>());
	std::cout << "result1= " << result1 << endl;
	std::cout << "result2= " << result2 << endl;

	// 除法
	double db1 = std::ranges::fold_left(view, 1, std::divides<double>());
	double db2 = std::ranges::fold_right(view, 1, std::divides<double>());
	std::cout << "db1= " << db1 << endl;
	std::cout << "db2= " << db2 << endl;

	// 自定义操作
	auto opt = [](int a, int b) {return  2 * a + b * 3; };
	result1 = std::ranges::fold_left(view, 0, opt);
	result2 = std::ranges::fold_right(view, 0, opt);
	std::cout << "result1= " << result1 << endl;
	std::cout << "result2= " << result2 << endl;

	// 字符串拼接
	auto view1 = view | std::views::transform([](int i) {return std::to_string(i) + ", "; });
	string	str1 = std::ranges::fold_left(view1, std::string(), std::plus<string>());
	string	str2 = std::ranges::fold_right(view1, std::string(), std::plus<string>());
	std::cout << "str1= " << str1 << endl;
	std::cout << "str2= " << str2 << endl;

	return 0;
}

java

java 复制代码
// 加法  
int result = IntStream.rangeClosed(1, 10)  
        .boxed()  
        .reduce(0, Integer::sum);  
System.out.println("result-> " + result);  
  
// 减法  
result = IntStream.rangeClosed(1, 10)  
        .boxed()  
        .reduce(0, (a, b) -> a - b);  
System.out.println("result-> " + result);  
  
// 乘法  
result = IntStream.rangeClosed(1, 10)  
        .boxed()  
        .reduce(1, (a, b) -> a * b);  
System.out.println("result-> " + result);  
  
// 除法  
result = IntStream.rangeClosed(1, 10)  
        .boxed()  
        .reduce(1, (a, b) -> a / b);  
System.out.println("result-> " + result);  
  
// 字符串拼接  
String str1 = IntStream.rangeClosed(1, 10)  
        .boxed()  
        .map(String::valueOf)  
        .collect(Collectors.joining(", ", "[", "]"));  
System.out.println("str1-> " + str1);

3、std::ranges::distance

用于计算范围或迭代器对之间距离

c++

cpp 复制代码
int main()
{
	system("chcp 65001");
	auto view = std::views::iota(1, 11)
		| std::views::filter([](int it) { return it % 3 == 0; });
	std::cout << "distance= " << std::ranges::distance(view) << endl;

	return 0;
}

java

java 复制代码
long count = IntStream.rangeClosed(1, 10)  
        .boxed()  
        .filter(it -> it % 3 == 0)  // 过滤  
        .count();  
System.out.println("count-> " + count);

4、std::ranges::find_if与std::ranges::find_last_if

c++

cpp 复制代码
int main()
{
	system("chcp 65001");
	auto view = std::views::iota(1, 11)
		| std::views::filter([](int it) { return it % 2 == 0; });

	// find_if
	auto result = std::ranges::find_if(view, [](int a) { return a > 5; });
	if (result != view.end()) {
		std::cout << "find_if= " << *result << endl;
	}

	// find_if_not
	result = std::ranges::find_if_not(view, [](int a) { return a > 5; });
	if (result != view.end()) {
		std::cout << "find_if_not= " << *result << endl;
	}

	// find_if_not
	auto ll = std::ranges::find_last_if(view, [](int a) { return a > 5; });
	if (!ll.empty())
	{
		std::cout << "find_last_if= " << *ll.begin() << endl;
	}

	// find_last_if_not
	ll = std::ranges::find_last_if_not(view, [](int a) { return a > 5; });
	if (!ll.empty())
	{
		std::cout << "find_last_if_not= " << *ll.begin() << endl;
	}

	return 0;
}

java

java 复制代码
int result = IntStream.rangeClosed(1, 20)  
        .boxed()  
        .filter(it -> it % 2 == 0)  // 过滤  
        .findFirst()  
        .orElse(0);  
System.out.println("result-> " + result);  
  
result = IntStream.rangeClosed(1, 20)  
        .boxed()  
        .filter(it -> it % 2 != 0)  // 过滤  
        .findFirst()  
        .orElse(0);  
System.out.println("result-> " + result);

5、std::ranges::all_of与std::ranges::any_of

c++

cpp 复制代码
int main()
{
	system("chcp 65001");
	auto view = std::views::iota(1, 11)
		| std::views::filter([](int it) { return it % 2 == 0; });

	// all_of 
	bool result = std::ranges::all_of(view, [](int a) { return a > 5; });
	std::cout << "all_of= " << boolalpha << result << endl;

	// any_of
	result = std::ranges::all_of(view, [](int a) { return a > 5; });
	std::cout << "any_of= " << boolalpha << result << endl;

	return 0;
}

java

java 复制代码
boolean result = IntStream.rangeClosed(1, 20)  
        .boxed()  
        .filter(it -> it % 2 == 0)  // 过滤  
        .allMatch(it -> it > 5);  
System.out.println("result-> " + result);  
  
result = IntStream.rangeClosed(1, 20)  
        .boxed()  
        .filter(it -> it % 2 != 0)  // 过滤  
        .anyMatch(it -> it > 5);  
System.out.println("result-> " + result);

result = IntStream.rangeClosed(1, 20)  
        .boxed()  
        .filter(it -> it % 2 != 0)  // 过滤  
        .noneMatch(it -> it > 5);  
System.out.println("result-> " + result);

6、std::ranges::for_each_n与std::ranges::for_each

特性 std::ranges::for_each std::ranges::for_each_n
输入 整个范围或迭代器对 起始迭代器 + 元素数量
适用场景 处理所有元素 处理指定数量的元素
边界安全 自动处理到范围结束 如果数量超过范围,行为未定义(需确保数量有效)
返回值 {end_iterator, function_object} {advanced_iterator, function_object}
范围版本 ✅ 有 ❌ 无(需手动传迭代器)
cpp 复制代码
int main() {
	// for_each
	auto view = std::views::iota(1, 21)
		| std::views::filter([](int it) { return it % 3 == 0; });
	std::ranges::for_each(view, [](const int it) {std::cout << "for_each-> " << it << endl; });

	// for_each_n [0,2]
	std::ranges::for_each_n(view.begin(), 2, [](const int it) {std::cout << "for_each_n [0,2]-> " << it << endl; });
	// for_each_n [1,3]
	std::ranges::for_each_n(++view.begin(), 2, [](const int it) {std::cout << "for_each_n [1,3]-> " << it << endl; });
	// for_each_n [2,4]
	std::ranges::for_each_n(std::next(view.begin(), 2), 2, [](const int it) {std::cout << "for_each_n [2,4]-> " << it << endl; });
	// for_each_n [end-2, end]
std::ranges::for_each_n(std::prev(view.end(), 2), 2, [](const int it) {std::cout << "for_each_n [end-2, end]-> " << it << endl; });

	return 0;
}

views相关

适配器 C++23 描述 Java Stream 等价
std::views::chunk 将范围分割为固定大小的块 自定义 Collector
std::views::chunk_by 根据谓词分组连续元素 Collectors.groupingBy()
std::views::slide 创建滑动窗口视图 自定义实现
std::views::join_with 连接范围并插入分隔符 Collectors.joining(delimiter)
std::views::adjacent 创建相邻元素元组 自定义实现
std::views::adjacent_transform 对相邻元素应用函数 自定义实现
std::views::cartesian_product 笛卡尔积 嵌套循环
std::views::zip_transform zip + transform 组合 Stream.zip() + map()

1、std::views::chunk

固定长度分块

cpp 复制代码
int main()
{
	system("chcp 65001");
	// 固定长度分块
	auto chunks = std::views::iota(1, 11)
		| std::views::chunk(5);
	for (auto chunk : chunks)
	{
		for (auto it : chunk)
		{
			std::cout << it << ", ";
		}
		std::cout << endl;
	}

	return 0;
}

2、std::views::chunk_by

根据‌条件将相邻的满足条件的元素分组到同一个块中

cpp 复制代码
int main()
{
	system("chcp 65001");
	// 按条件将相邻的满足条件的元素划分到一组
	auto chunks = std::views::iota(1, 11)
		| std::views::chunk_by([](int a, int b) {return a + b < 10; });
	for (auto chunk : chunks)
	{
		for (auto it : chunk)
		{
			std::cout << it << ", ";
		}
		std::cout << endl;
	}

	return 0;
}

3、std::views::slide

将范围分割成多个重叠的固定大小子范围,每个子窗口相对于前一个窗口滑动一个位置

cpp 复制代码
int main()
{
	system("chcp 65001");
	// 指定元素个数划分
	auto wins = std::views::iota(1, 11)
		| std::views::slide(4);
	for (auto win : wins)
	{
		for (auto it : win)
		{
			std::cout << it << ", ";
		}
		// 计算窗口内元素的平均值
		double avg = std::accumulate(win.begin(), win.end(), 0.0) / win.size();
		std::cout << " ->avg: " << avg << std::endl;
		std::cout << endl;
	}

	return 0;
}

4、std::views::join_with

主要作用是将二维容器(如 vector<vector<T>>)转换为一维视图,并在每个子范围之间插入指定的分隔符元素或子范围。它是 std::ranges::views::join 的扩展版本,提供了更灵活的连接逻辑

cpp 复制代码
int main()
{
	system("chcp 65001");
	// 字符作为分割符号
	auto line1 = std::views::iota(1, 11)
		| std::views::transform([](int a) {return std::to_string(a); })
		| std::views::join_with(',');
	for (auto it : line1)
	{
		std::cout << it;
	}
	std::cout << endl;

	// 字符串作为分割符号
	auto str = std::views::iota(1, 11)
		| std::views::transform([](int a) { std::vector<std::string> vec = { std::to_string(a) }; return vec; })
		| std::views::join_with(", ");
	for (auto it : str)
	{
		std::cout << it;
	}
	std::cout << endl;

	// 字符作为分割符号
	std::vector<std::string> words = { "hello", "world" };
	auto sentence1 = words | std::views::join_with(',');
	for (auto it : sentence1)
	{
		std::cout << it;
	}
	std::cout << endl;

	// 字符串作为分割符号
	auto sentence2 = words
		| std::views::transform([](string a) {std::vector<std::string> vec = { a }; return vec; })
		| std::views::join_with(", ");
	for (auto it : sentence2)
	{
		std::cout << it;
	}
	std::cout << endl;

	// std::vector作为分隔符
	std::vector<std::vector<int>> matrix = { {1, 2}, {3, 4}, {5, 6} };
	auto flattened = matrix | std::views::join_with(0);
	// auto flattened = matrix | std::views::join_with(std::vector<int>{0});
	for (auto it : flattened)
	{
		std::cout << it;
	}
	std::cout << endl;

	return 0;
}

5、std::views::adjacent

将输入范围转换为一个由相邻元素组成的元组视图

cpp 复制代码
int main()
{
	system("chcp 65001");
	// 生成二元组
	auto tuple2List = std::views::iota(1, 11)
		| std::views::adjacent<2>;
	for (auto [a, b] : tuple2List)
	{
		std::cout << "[" << a << ", " << b << "], ";
		std::cout << endl;
	}

	// 生成三元组
	auto tuple3List = std::views::iota(1, 11)
		| std::views::adjacent<3>;
	for (auto [a, b, c] : tuple3List)
	{
		std::cout << "[" << a << ", " << b << ", " << c << "], ";
		std::cout << endl;
	}


	return 0;
}

6、std::views::adjacent_transform

可以std::views::adjacent 与 std::views::transform组合使用

cpp 复制代码
int main()
{
	system("chcp 65001");

	// adjacent_transform
	auto avgList = std::views::iota(1, 11)
		| std::views::adjacent_transform<3>(
			[](auto... args) {
				return (args + ...) / 3.0;
			}
		);

	for (double avg : avgList) {
		std::cout << "auto-> avg: " << avg << std::endl;
	}

	// 指定参数
	auto aaa = std::views::iota(1, 11)
		| std::views::adjacent_transform<3>(
			[](int a, int b, int c) {
				return (a + b + c) / 3.0;
			}
		);

	for (double avg : aaa) {
		std::cout << "aaa-> avg: " << avg << std::endl;
	}

	// std::views::adjacent + std::views::transform组合使用
	auto bbb = std::views::iota(1, 11)
		| std::views::adjacent<3>
		| std::views::transform([](auto tuple) {  auto [a, b, c] = tuple; return (a + b + c) / 3.0; });
	for (double avg : bbb) {
		std::cout << "bbb-> avg: " << avg << std::endl;
	}

	return 0;
}

7、std::views::cartesian_product

生成多个范围的笛卡尔积视图

cpp 复制代码
int main()
{
	system("chcp 65001");

	std::vector<char> aaa = { 'a', 'b' };
	std::vector<int> bbb = { 1, 2 };
	std::vector<std::string> ccc = { "hello", "world" };

	// 生成笛卡尔积
	auto result = std::views::cartesian_product(aaa, bbb, ccc);

	for (const auto& tuple : result) {
		char a = std::get<0>(tuple);
		int b = std::get<1>(tuple);
		std::string c = std::get<2>(tuple);
		std::cout << a << " - " << b << " - " << c << std::endl;
	}

	return 0;
}

8、std::views::zip_transform

可以使用std::views::zip 与 std::views::transform组合

cpp 复制代码
int main()
{
	system("chcp 65001");

	std::vector<int> aa = { 1, 2, 3 };
	std::vector<char> bb = { 'A', 'B', 'C' };
	std::vector<std::string> cc = { "one", "two", "three" };

	// 将三个范围的对应元素打包成元组
	auto abc = std::views::zip(aa, bb, cc);
	for (auto [a, b, c] : abc) {
		std::cout << a << " - " << b << " - " << c << std::endl;
	}


	// std::views::zip_transform
	auto result = std::views::zip_transform([](int a, char b, string c) { return std::to_string(a) + b + c; },
		aa, bb, cc);
	for (auto it : result)
	{
		std::cout << it << endl;
	}

	// std::views::zip + std::views::transform
	auto rtn = std::views::zip(aa, bb, cc)
		| std::views::transform([](auto pair) {
		auto [a, b, c] = pair;
		return std::to_string(a) + b + c;
			});
	for (auto it : rtn)
	{
		std::cout << it << endl;
	}

	return 0;
}
相关推荐
会飞的胖达喵2 小时前
Qt CMake 项目构建配置详解
开发语言·qt
一个尚在学习的计算机小白2 小时前
java集合
java·开发语言
IUGEI2 小时前
synchronized的工作机制是怎样的?深入解析synchronized底层原理
java·开发语言·后端·c#
z***I3942 小时前
Java桌面应用案例
java·开发语言
来来走走2 小时前
Android开发(Kotlin) LiveData的基本了解
android·开发语言·kotlin
一个不知名程序员www2 小时前
算法学习入门---vector(C++)
c++·算法
明洞日记2 小时前
【数据结构手册002】动态数组vector - 连续内存的艺术与科学
开发语言·数据结构·c++
福尔摩斯张2 小时前
《C 语言指针从入门到精通:全面笔记 + 实战习题深度解析》(超详细)
linux·运维·服务器·c语言·开发语言·c++·算法
Dream it possible!3 小时前
LeetCode 面试经典 150_二叉搜索树_二叉搜索树的最小绝对差(85_530_C++_简单)
c++·leetcode·面试