news 2026/2/14 17:46:46

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/2/6 10:56:48

飞书文档批量导出终极方案:企业知识库迁移效率提升10倍

飞书文档批量导出终极方案&#xff1a;企业知识库迁移效率提升10倍 【免费下载链接】feishu-doc-export 项目地址: https://gitcode.com/gh_mirrors/fe/feishu-doc-export 当你的团队积累了数百份飞书文档&#xff0c;面临知识库迁移或备份需求时&#xff0c;手动逐一下…

作者头像 李华
网站建设 2026/2/6 17:48:15

【Open-AutoGLM使用全攻略】:从零入门到实战精通的5大核心技巧

第一章&#xff1a;Open-AutoGLM怎么用Open-AutoGLM 是一个开源的自动化代码生成框架&#xff0c;专注于通过自然语言描述生成高质量代码片段。它基于 GLM 大语言模型构建&#xff0c;支持多语言输出与上下文感知优化&#xff0c;适用于快速原型开发、教学辅助和低代码平台集成…

作者头像 李华
网站建设 2026/2/12 11:42:44

六网盘直链解析工具:浏览器中实现高速下载的全能助手

在数字时代&#xff0c;我们经常需要从各种网盘下载重要文件&#xff0c;但繁琐的客户端安装和缓慢的网页下载体验让人头疼。今天介绍的这款浏览器脚本工具&#xff0c;正是为解决这一痛点而生&#xff0c;让你在浏览器中就能实现高速下载&#xff0c;无需任何额外软件。 【免费…

作者头像 李华
网站建设 2026/2/13 8:24:36

终极音频解码神器:qmcdump一键解锁QQ音乐加密文件

终极音频解码神器&#xff1a;qmcdump一键解锁QQ音乐加密文件 【免费下载链接】qmcdump 一个简单的QQ音乐解码&#xff08;qmcflac/qmc0/qmc3 转 flac/mp3&#xff09;&#xff0c;仅为个人学习参考用。 项目地址: https://gitcode.com/gh_mirrors/qm/qmcdump 还在为QQ音…

作者头像 李华
网站建设 2026/2/9 1:10:11

终极免费Windows系统优化工具:一键加速完整使用指南

终极免费Windows系统优化工具&#xff1a;一键加速完整使用指南 【免费下载链接】OpenSpeedy 项目地址: https://gitcode.com/gh_mirrors/op/OpenSpeedy 还在为电脑卡顿、程序响应慢而烦恼吗&#xff1f;想要一款真正免费且高效的Windows系统加速工具吗&#xff1f;Ope…

作者头像 李华