news 2026/10/3 3:35:19

C++20 Ranges与函数式编程举例

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C++20 Ranges与函数式编程举例

我来详细介绍C++20 Ranges中的这些操作,并给出水仙花数的示例。

C++20 Ranges 核心操作

  1. transform - 对每个元素应用函数
#include<ranges>#include<vector>#include<iostream>autonums=std::vector{1,2,3,4,5};autodoubled=nums|std::views::transform([](intx){returnx*2;});// 结果: 2, 4, 6, 8, 10
  1. filter - 过滤满足条件的元素
autoeven=nums|std::views::filter([](intx){returnx%2==0;});// 结果: 2, 4
  1. take - 取前n个元素
autofirst3=nums|std::views::take(3);// 结果: 1, 2, 3
  1. sort 和 unique - 排序和去重

注意:这些不是视图,而是操作

#include<algorithm>std::ranges::sort(nums);// 原地排序autounique_view=nums|std::views::unique;// 注意:unique_view只是视图,不会改变原容器
  1. sum 计算

C++20 Ranges中没有直接的sum,但可以配合std::accumulate:

#include<numeric>inttotal=std::accumulate(nums.begin(),nums.end(),0);

完整示例:水仙花数集合

#include<iostream>#include<vector>#include<ranges>#include<cmath>#include<algorithm>// 判断是否为水仙花数(n位数,各位数字的n次方之和等于本身)boolisNarcissistic(intnum){intsum=0;inttemp=num;intn=static_cast<int>(std::to_string(num).length());while(temp>0){intdigit=temp%10;sum+=static_cast<int>(std::pow(digit,n));temp/=10;}returnsum==num;}// 生成水仙花数集合std::vector<int>getNarcissisticNumbers(intlimit){usingnamespacestd::ranges;usingnamespacestd::views;// 生成1到limit的序列autonumbers=iota(1,limit+1);// 过滤出水仙花数autonarcissistic=numbers|filter(isNarcissistic);// 转换为vector并返回returnstd::vector<int>(narcissistic.begin(),narcissistic.end());}// 更优雅的版本:使用管道操作autogetNarcissisticNumbersRange(intstart,intend){returnstd::views::iota(start,end+1)|std::views::filter(isNarcissistic);}intmain(){std::cout<<"水仙花数 (1-1000):\n";// 方法1:获取vectorautonarcissistic1=getNarcissisticNumbers(1000);for(intnum:narcissistic1){std::cout<<num<<" ";}std::cout<<"\n\n";// 方法2:直接使用range视图(惰性求值)std::cout<<"使用range视图:\n";for(intnum:getNarcissisticNumbersRange(1,10000)){std::cout<<num<<" ";}std::cout<<"\n\n";// 方法3:结合更多操作std::cout<<"三位数的水仙花数:\n";autothreeDigitNarcissistic=std::views::iota(100,1000)|std::views::filter(isNarcissistic);for(intnum:threeDigitNarcissistic){std::cout<<num<<" ";}std::cout<<"\n";return0;}

更复杂的组合示例

#include<iostream>#include<vector>#include<ranges>#include<algorithm>voidcomplexExample(){usingnamespacestd::ranges;usingnamespacestd::views;std::vector<int>numbers{153,370,371,407,123,456,789,1634};// 组合多个操作:过滤、排序、去重autoprocessed=numbers|filter([](intx){returnx>=100&&x<=999;})// 只取三位数|transform([](intx){returnx+1;})// 每个数加1|common;// 转换为common_range以便排序// 转换为vector进行排序(range视图本身是惰性的)std::vector<int>result(processed.begin(),processed.end());std::ranges::sort(result);std::cout<<"处理后的水仙花数+1并排序:\n";for(intnum:result){std::cout<<num<<" ";}std::cout<<"\n";}intmain(){complexExample();return0;}

关键点总结

  1. 惰性求值:Ranges视图是惰性的,只有在遍历时才计算
  2. 管道操作符 |:使代码更易读
  3. 视图 vs 操作:
    · 视图(views):transform, filter, take等,返回视图对象
    · 操作(algorithms):sort, unique等,可能修改容器
  4. 性能优势:避免中间容器的创建,提高性能
  5. 可组合性:可以轻松组合多个操作

水仙花数的常见值:153, 370, 371, 407, 1634, 8208, 9474, 54748, …

你说得对!我们可以用 transform 来计算水仙花数的各位数字幂次和。让我重写水仙花数判断函数,充分利用 Ranges 的特性:

#include<iostream>#include<vector>#include<ranges>#include<cmath>#include<numeric>#include<string>#include<algorithm>// 使用Ranges的transform计算各位数字的幂次和boolisNarcissistic(intnum){usingnamespacestd::ranges;usingnamespacestd::views;std::string numStr=std::to_string(num);intn=numStr.length();// 将字符串转换为各位数字autodigits=numStr|transform([](charc){returnc-'0';});// 计算每位数字的n次方之和autosum=std::accumulate(digits.begin(),digits.end(),0,[n](inttotal,intdigit){returntotal+static_cast<int>(std::pow(digit,n));});returnsum==num;}// 或者更函数式的写法boolisNarcissisticFunctional(intnum){usingnamespacestd::ranges;usingnamespacestd::views;std::string numStr=std::to_string(num);intn=numStr.length();// 一行代码完成:将数字转换为字符串,提取每位数字,计算幂次和autopowerSum=std::accumulate(numStr.begin(),numStr.end(),0,[n](inttotal,charc){intdigit=c-'0';returntotal+static_cast<int>(std::pow(digit,n));});returnpowerSum==num;}// 另一种方法:使用整数运算配合rangesboolisNarcissisticRangeOnly(intnum){usingnamespacestd::views;intoriginal=num;intn=static_cast<int>(std::to_string(num).length());// 创建一个从num提取各位数字的生成器autodigits=[num]()mutable{returntransform_view{iota(0)|take_while([num](int){returnnum>0;}),[&num](int){intdigit=num%10;num/=10;returndigit;}};}();// 计算幂次和intsum=0;for(intdigit:digits){sum+=static_cast<int>(std::pow(digit,n));}returnsum==original;}// 使用管道操作生成水仙花数范围autogenerateNarcissisticNumbers(intstart,intend){usingnamespacestd::ranges;usingnamespacestd::views;returniota(start,end+1)|filter(isNarcissistic)|common;// 转换为common_range}// 更复杂的示例:使用transform处理结果voidnarcissisticTransformExample(){usingnamespacestd::ranges;usingnamespacestd::views;std::cout<<"水仙花数及其平方:\n";autonarcissisticNumbers=iota(100,10000)|filter(isNarcissistic)|transform([](intn){returnstd::make_pair(n,n*n);// 返回原数和平方});for(auto[num,square]:narcissisticNumbers){std::cout<<num<<" -> "<<square<<"\n";}}// 使用transform计算每个水仙花数的各位数字voidanalyzeNarcissisticNumbers(){usingnamespacestd::ranges;usingnamespacestd::views;std::cout<<"\n水仙花数各位数字分析:\n";autoanalysis=iota(100,10000)|filter(isNarcissistic)|transform([](intnum){std::string str=std::to_string(num);intn=str.length();// 提取各位数字autodigits=str|transform([](charc){returnc-'0';})|std::ranges::to<std::vector<int>>();// 计算幂次autopowers=digits|transform([n](intd){returnstatic_cast<int>(std::pow(d,n));})|std::ranges::to<std::vector<int>>();returnstd::make_tuple(num,digits,powers);});for(constauto&[num,digits,powers]:analysis){std::cout<<num<<" = ";for(size_t i=0;i<digits.size();++i){std::cout<<digits[i]<<"^"<<digits.size();if(i<digits.size()-1)std::cout<<" + ";}std::cout<<" = ";for(size_t i=0;i<powers.size();++i){std::cout<<powers[i];if(i<powers.size()-1)std::cout<<" + ";}std::cout<<"\n";}}intmain(){std::cout<<"三位数水仙花数:\n";// 生成并输出水仙花数autonarcissistic=generateNarcissisticNumbers(100,1000);for(intnum:narcissistic){std::cout<<num<<" ";}std::cout<<"\n\n";// 使用transform处理结果narcissisticTransformExample();// 详细分析analyzeNarcissisticNumbers();// 测试各种方法的一致性std::cout<<"\n测试各种实现的一致性:\n";for(intnum:{153,370,371,407,1634,8208,9474}){boolr1=isNarcissistic(num);boolr2=isNarcissisticFunctional(num);boolr3=isNarcissisticRangeOnly(num);std::cout<<num<<": "<<r1<<" "<<r2<<" "<<r3<<" (所有方法应该一致)\n";}return0;}

更简化的版本(C++23)

如果你的编译器支持C++23,可以更简洁:

#include<iostream>#include<ranges>#include<cmath>#include<numeric>// C++23简化版autoisNarcissisticCpp23(intnum)->bool{std::string s=std::to_string(num);intn=s.length();// 使用fold计算总和returnstd::ranges::fold_left(s,0,[n](intsum,charc){intdigit=c-'0';returnsum+static_cast<int>(std::pow(digit,n));})==num;}// 使用C++23的to<>将range转为容器autogetNarcissisticNumbersCpp23(intmax){usingnamespacestd::ranges;usingnamespacestd::views;returniota(1,max+1)|filter(isNarcissisticCpp23)|to<std::vector<int>>();}intmain(){autonumbers=getNarcissisticNumbersCpp23(10000);std::cout<<"水仙花数 (1-10000):\n";for(intnum:numbers){std::cout<<num<<" ";}std::cout<<"\n";return0;}

关键改进点:

  1. 使用transform提取数字:将字符串转换为数字序列
  2. 结合accumulate计算和:使用标准算法计算幂次和
  3. 函数式风格:更符合Ranges的设计理念
  4. 可组合性:可以轻松与其他Ranges操作组合

性能考虑:

虽然使用transform和字符串转换的方法很优雅,但性能可能不如直接使用整数运算。在实际应用中,可以根据需求选择:

· 代码简洁性优先:使用字符串+transform方法
· 性能优先:使用传统的整数运算方法
· 学习/演示:展示Ranges的各种用法

这样改写后,水仙花数的判断逻辑完全融入了Ranges的函数式编程风格!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/2 3:00:56

OpenSpeedy命令行参数配置完整指南:轻松掌握游戏加速工具

OpenSpeedy命令行参数配置完整指南&#xff1a;轻松掌握游戏加速工具 【免费下载链接】OpenSpeedy 项目地址: https://gitcode.com/gh_mirrors/op/OpenSpeedy OpenSpeedy是一款功能强大的开源游戏加速工具&#xff0c;通过Hook Windows系统时间函数来实现游戏帧率的突破…

作者头像 李华
网站建设 2026/10/2 3:00:52

Switch手柄PC连接实战:从零到精通的全能指南

还在为Switch手柄在电脑上无法正常使用而烦恼吗&#xff1f;今天我将带你深入探索BetterJoy工具的奥秘&#xff0c;让你轻松实现各类Switch控制器在PC上的完美兼容。无论你是游戏玩家还是模拟器爱好者&#xff0c;这篇文章都将成为你的得力助手。 【免费下载链接】BetterJoy Al…

作者头像 李华
网站建设 2026/10/2 22:28:36

红队视角深度解析:内网攻破的全步骤拆解

【干货收藏】内网攻防实战&#xff1a;从红队视角构建企业安全防御体系 内网安全是企业核心资产与生存发展的关键防线&#xff0c;面临APT攻击、供应链漏洞等高级威胁。企业需构建多层次防御体系&#xff0c;培养专业安全人才。《内网攻防实战图谱》从红队视角系统讲解内网攻防…

作者头像 李华
网站建设 2026/10/2 22:28:28

如何快速配置AdGuardHomeRules:打造纯净网络环境完整指南

还在为网页弹窗广告、视频前贴片广告、App内置广告而烦恼吗&#xff1f;AdGuardHomeRules为你提供超过百万条广告拦截规则的终极解决方案&#xff0c;让上网体验彻底告别广告干扰。这款开源工具简单易用&#xff0c;完全免费&#xff0c;能够为你的所有设备打造纯净的网络环境。…

作者头像 李华
网站建设 2026/10/1 23:43:57

如何在3分钟内解锁网易云音乐NCM加密文件实现音频自由?

如何在3分钟内解锁网易云音乐NCM加密文件实现音频自由&#xff1f; 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 你是否曾经在网易云音乐下载了喜欢的歌曲&#xff0c;却发现只能在特定客户端播放&#xff0c;无法在其他设备上享受…

作者头像 李华
网站建设 2026/10/2 4:16:14

阴阳师自动化脚本2025完整使用手册:从零基础到高手进阶

阴阳师自动化脚本2025完整使用手册&#xff1a;从零基础到高手进阶 【免费下载链接】OnmyojiAutoScript Onmyoji Auto Script | 阴阳师脚本 项目地址: https://gitcode.com/gh_mirrors/on/OnmyojiAutoScript 还在为阴阳师每日重复性任务感到疲惫吗&#xff1f;&#x1f…

作者头像 李华