C#累加器函数Aggregate用法 讲解
Enumerable.Aggregate 扩展方法在System.Linq命名空间中,是Enumerable类的第一个方法(按字母顺序排名),但确是Enumerable里面相对复杂的方法。
MSDN对它的说明是:对序列应用累加器函数。备注中还有一些说明,大意是这个方法比较复杂,一般情况下用Sum、Max、Min、Average就可以了。
看看下面的代码,有了Sum,谁还会用Aggregate呢!
也很简单吧,就是一个循环!前面lambda表达式中参数a, n 分别对应current, enumerator.Current,对照一下,还是很好理解的。
现在我们想求整数数组中位置为偶数的数的和(间隔求和),可以用Where配合Sum:
public static void Test5()
{
int[] nums = new int[] { 10, 20, 30, 40, 50 };
int sum1 = nums.Where((n, i) => i % 2 == 0).Sum();//10 + 30 + 50
}
这个Where扩展设计的很好,它不但能带出某项的值“n”,还能带出项的位置“i”。
Aggregate可不行!我们来改进一下:
//改进的Aggerate扩展(示例代码,实际使用请添加空值检查)
public static TSource Aggregate<TSource>(this IEnumerable<TSource> source, Func<TSource, TSource, int, TSource> func)
{
int index = 0;
using (IEnumerator<TSource> enumerator = source.GetEnumerator())
{
enumerator.MoveNext();
index++;
TSource current = enumerator.Current;
while (enumerator.MoveNext())
current = func(current, enumerator.Current, index++);
return current;
}
}
改进后的Aggregate更加强大,前面的求偶数位置数和的算法可以写成下面的样子:
public static void Test6()
{
int[] nums = new int[] { 10, 20, 30, 40, 50 };
int sum2 = nums.Aggregate((a, c, i) => a + i%2 == 0 ? c : 0 );//10 + 30 + 50
}
可能不够简洁,但它一个函数代替了Where和Sum。所在位置“i“的引入给Aggregate带来了很多新的活力,也增加了它的应用范围!
《使用“初中知识”实现查找重复最优算法 + 最终极限算法》中最后提出的“最终极限算法”,用上这里改进的Aggregate扩展,也可以甩开Select和Sum,更加精简一步了:
public static void Test7()
{
//1~n放在含有n+1个元素的数组中,只有唯一的一个元素值重复,最简算法找出重复的数
int[] array = new int[] { 1, 3, 2, 3, 4, 5 };
//原极限算法
int repeatedNum1 = array.Select((i, j) => i - j).Sum();
//最新极限算法
int repeatedNum2 = array.Aggregate((a, n, i) => a + n - i);
}
public static void Test1()
{
int[] nums = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; int sum1 = nums.Sum();
int sum2 = nums.Aggregate((i,j)=>i+j);
}
同是求和,Sum不再需要额外参数,而Aggregate确还要将一个lambda作为参数。因为用起来麻烦,操作太低级,Aggregate渐渐被大多人忽视了...
实际上Aggregate因为“低级”,功能确是很强大的,通过它可以简化很多聚合运算。
首先来看对Aggregate组装字符串的问题:
public static void Test2()
{
string[] words = new string[] { "Able", "was", "I", "ere", "I", "saw", "Elba"};
string s = words.Aggregate((a, n) => a + " " + n);
Console.WriteLine(s);
}
输出结果是:Able was I ere I saw Elba (注:出自《大国崛起》,狄娜最后讲述了拿破仑一句经典)。
当然考虑性能的话还是用StringBuilder吧,这里主要介绍用法。这个Sum做不到吧!
Aggregate还可以将所有字符串倒序累加,配合String.Reverse扩展可以实现整个句子的倒序输出:
public static void Test3()
{
string[] words = new string[] { "Able", "was", "I", "ere", "I", "saw", "Elba"};
string normal = words.Aggregate((a, n) => a + " " + n);
string reverse = words.Aggregate((a, n) => n.Reverse() + " " + a); Console.WriteLine("正常:" + normal);
Console.WriteLine("倒置:" + reverse);
}
// 倒置字符串,输入"abcd123",返回"321dcba"
public static string Reverse(this string value)
{
char[] input = value.ToCharArray();
char[] output = new char[value.Length];
for (int i = 0; i < input.Length; i++)
output[input.Length - 1 - i] = input[i];
return new string(output);
}
看下面,输出结果好像不太对:
怎么中间的都一样,两的单词首尾字母大小写发生转换了呢?!
仔细看看吧,不是算法有问题,是输入“有问题”。搜索一下“Able was I ere I saw Elba”,这可是很有名的英文句子噢!
Aggregate还可以实现异或(^)操作:
public static void Test4()
{
byte[] data = new byte[] { 0x31, 0x32, 0x33, 0x34, 0x35 };
byte checkSum = data.Aggregate((a, n) => (byte)(a ^ n));
}
对经常作串口通信的朋友比较实用。
看来Aggregate也是比较“简单易用”的,深入一步来看看它是怎么实现的吧,使用Reflector,反编译一下System.Core.dll。
以下代码取自反编译结果,为了演示删除了其中的空值判断代码:
| public static TSource Aggregate<TSource>(this IEnumerable<TSource> source, Func<TSource, TSource, TSource> func) { using (IEnumerator<TSource> enumerator = source.GetEnumerator()) { enumerator.MoveNext(); TSource current = enumerator.Current; while (enumerator.MoveNext()) current = func(current, enumerator.Current); return current; } } |
C#累加器函数Aggregate用法 讲解的更多相关文章
- tf.transpose函数的用法讲解
tf.transpose函数中文意思是转置,对于低维度的转置问题,很简单,不想讨论,直接转置就好(大家看下面文档,一看就懂). tf.transpose(a, perm=None, name='tra ...
- python中map()函数的用法讲解
map函数的原型是map(function, iterable, -),它的返回结果是一个列表. 参数function传的是一个函数名,可以是python内置的,也可以是自定义的. 参数iterabl ...
- MySQL中 IFNULL、NULLIF和ISNULL函数的用法
mysql 中 ifnull().nullif().isnull()函数的用法讲解: 一.IFNULL(expr1,expr2)用法: 假如expr1不为NULL,则 IFNULL() 的返回值为ex ...
- Linq扩展方法之Aggregate 对序列应用累加器函数
Linq扩展方法之Aggregate 对序列应用累加器函数; 函数模板:// 函数名:对序列应用累加器函数. // Parameters:参数要求 // source:要聚合的 System.Col ...
- LINQ中的Aggregate用法总结
Aggregate这个语法可以做一些复杂的聚合运算,例如累计求和,累计求乘积.它接受2个参数,一般第一个参数是称为累积数(默认情况下等于第一个值),而第二个代表了下一个值.第一次计算之后,计算的结果会 ...
- python中open函数的用法
用法如下: name = open('errname.txt','w')name.readline()name.close() 1.看下第一行的代码 用来访问磁盘中存放的文件,可以进行读写等操作,例如 ...
- 详解php 获取文件名basename()函数的用法
PHP 中basename()函数给出一个包含有指向一个文件的全路径的字符串,此函数返回基本的文件名,本篇文章收集了关于使用PHP basename()函数获取文件名的几篇文章,希望对大家理解使用PH ...
- PHP截取字符串函数substr()函数实例用法详解
在PHP中有一项非常重要的技术,就是截取指定字符串中指定长度的字符.PHP对于字符串截取可以使用PHP预定义函数substr()函数来实现.下面就来介绍一下substr()函数的语法及其应用. sub ...
- 有关日期的函数操作用法总结,to_date(),trunc(),add_months();
相关知识链接: Oracle trunc()函数的用法 oracle add_months函数 Oracle日期格式转换,tochar(),todate() №2:取得当前日期是一个星期中的第几天,注 ...
随机推荐
- JZ2440 裸机驱动 第14章 ADC和触摸屏接口
本章目标: 了解S3C2410/S3C2440和触摸屏的结构: 了解电阻触摸屏的工作原理和等效电路图: 了解S3C2410/S3C2440触摸屏控制器的多种工作模式: ...
- Zigbee 的 mesh功能设置
1. 在编译选项中加入ZIGBEEPRO 最大的节点深度为20,网络模式为mesh网络 如果不配置,则为HOME_CONTROLS,支持5级路由深度,每个路由器最多可连接20个节点(最多包括6个路由器 ...
- 添加BAUD_4800
1.hal_uart.h 添加 #define HAL_UART_BR_4800 0x05 2.mt_uart.h 修改 #define MT_UART_DEFAULT_BAUDRATE HAL_UA ...
- NET中调用存储过程(Output、Input)
NET中调用存储过程(Output.Input) .NET中调用存储过程(Output.Input) 带输入输出参数的存储过程 带输入输出参数的存储过程 create procedure itemCo ...
- JSP+JavaBean+Servlet技术(MVC模型)
一,Servlet开发用户在浏览器中输入一个网址并回车,浏览器会向服务器发送一个HTTP请求.服务器端程序接受这个请求,并对请求进行处理,然后发送一个回应.浏览器收到回应,再把回应的内容显示出来.这种 ...
- QWidget背景(透明)问题
一. 背景設定為成黑色,前景色設為白色. 方法一.paltette方式,經測試,該方法不會影響到其他控制元件,建議使用 QPalette bgpal = palette();bgpal.setColo ...
- Eclipse/MyEclipse连接Hadoop集群出现:Unable to ... ... org.apache.hadoop.security.AccessControlExceptiom:Permission denied问题
问题详细如下: 解决办法: <property> <name>dfs.premissions</name> <value>false</value ...
- 转!!!解释Eclipse下Tomcat项目部署路径问题(.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps)
1.配置eclipse的开发环境,配置jdk的安装路径和tomcat安装路径. 2.在eclipse下建立Dynamic Web Project工程zhgy,在使用eclipse中new一个tomca ...
- [转] oracle 数据库 SQL plus 连接方法
http://hi.baidu.com/zzy382/item/a5b197f97a38e01ba7298832 之前电脑上安装了一个 Oracle 有一段时间没用,就把密码给忘了,按上面链接里的操 ...
- 从Tomcat无法正常关闭讲讲Java线程关闭问题【转载】
正常情况下,会优先采用catalina.sh stop来停止Tomcat实例,这样可以让服务有机会处理完请求,并做好善后工作. 但如果通过catalina.sh stop命令无法关闭Tomcat实例, ...