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

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的函数式编程风格!

http://www.cnnetsun.cn/news/184234.html

相关文章:

  • OpenSpeedy命令行参数配置完整指南:轻松掌握游戏加速工具
  • Switch手柄PC连接实战:从零到精通的全能指南
  • 红队视角深度解析:内网攻破的全步骤拆解
  • 如何快速配置AdGuardHomeRules:打造纯净网络环境完整指南
  • 如何在3分钟内解锁网易云音乐NCM加密文件实现音频自由?
  • 阴阳师自动化脚本2025完整使用手册:从零基础到高手进阶
  • AdGuard Home广告拦截配置完整教程:百万规则打造纯净网络
  • 2025年安卓设备VS Code终极部署手册:打造移动开发新纪元
  • springboot人口老龄化社区活动老年人服务和管理平台 _xl261auu
  • springboot四川自驾游攻略管理系统_3ra412wd
  • 网易云音乐NCM解密工具:三步解锁你的专属音乐库
  • 网盘直链下载助手终极指南:免客户端高速下载全攻略
  • 网易云音乐NCM文件终极解密:从加密到无损转换全攻略
  • Poppler Windows工具集:PDF处理效率的革命性突破
  • 5分钟彻底解锁网易云音乐NCM格式:从加密到无损的完美转换
  • iOS微信自动抢红包插件技术解析与使用指南
  • DLSS版本管理神器:DLSS Swapper完全使用指南
  • 六音音源修复版完整教程:轻松解决洛雪音乐播放问题
  • 如何快速修复洛雪音乐六音音源失效问题
  • 去论文AI痕迹别乱改!这4类句子最容易暴露,一定要重点润色
  • 知网降AI率保姆级教程:亲测有效,稳过检测!(2025最新版)
  • Vue-Office完全指南:5分钟实现Web端Office文件在线预览
  • GitHub汉化插件终极指南:5分钟让GitHub说中文
  • ncmdump终极指南:3步解锁网易云音乐NCM格式限制
  • Ollydbg下载及安装实战案例:快速搭建用户层调试器
  • 制造业数字化服务商如何助力企业转型?
  • Iwara视频下载工具完全指南:从零开始掌握高效下载技巧
  • NCM音频格式转换终极指南:轻松解锁网易云音乐加密文件
  • Anything-LLM:3分钟打造属于你的智能文档聊天机器人
  • BetterGI完整使用指南:从零开始掌握原神自动化