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用法 讲解的更多相关文章

  1. tf.transpose函数的用法讲解

    tf.transpose函数中文意思是转置,对于低维度的转置问题,很简单,不想讨论,直接转置就好(大家看下面文档,一看就懂). tf.transpose(a, perm=None, name='tra ...

  2. python中map()函数的用法讲解

    map函数的原型是map(function, iterable, -),它的返回结果是一个列表. 参数function传的是一个函数名,可以是python内置的,也可以是自定义的. 参数iterabl ...

  3. MySQL中 IFNULL、NULLIF和ISNULL函数的用法

    mysql 中 ifnull().nullif().isnull()函数的用法讲解: 一.IFNULL(expr1,expr2)用法: 假如expr1不为NULL,则 IFNULL() 的返回值为ex ...

  4. Linq扩展方法之Aggregate 对序列应用累加器函数

    Linq扩展方法之Aggregate  对序列应用累加器函数; 函数模板:// 函数名:对序列应用累加器函数. // Parameters:参数要求 // source:要聚合的 System.Col ...

  5. LINQ中的Aggregate用法总结

    Aggregate这个语法可以做一些复杂的聚合运算,例如累计求和,累计求乘积.它接受2个参数,一般第一个参数是称为累积数(默认情况下等于第一个值),而第二个代表了下一个值.第一次计算之后,计算的结果会 ...

  6. python中open函数的用法

    用法如下: name = open('errname.txt','w')name.readline()name.close() 1.看下第一行的代码 用来访问磁盘中存放的文件,可以进行读写等操作,例如 ...

  7. 详解php 获取文件名basename()函数的用法

    PHP 中basename()函数给出一个包含有指向一个文件的全路径的字符串,此函数返回基本的文件名,本篇文章收集了关于使用PHP basename()函数获取文件名的几篇文章,希望对大家理解使用PH ...

  8. PHP截取字符串函数substr()函数实例用法详解

    在PHP中有一项非常重要的技术,就是截取指定字符串中指定长度的字符.PHP对于字符串截取可以使用PHP预定义函数substr()函数来实现.下面就来介绍一下substr()函数的语法及其应用. sub ...

  9. 有关日期的函数操作用法总结,to_date(),trunc(),add_months();

    相关知识链接: Oracle trunc()函数的用法 oracle add_months函数 Oracle日期格式转换,tochar(),todate() №2:取得当前日期是一个星期中的第几天,注 ...

随机推荐

  1. win7 配置微软的深度学习caffe

    win7 配置微软的深度学习caffe   官方下载: https://github.com/Microsoft/caffe 然后 直接修改caffe目录下的windows目录下的项目的props文件 ...

  2. Asp.Net中使用Newtonsoft.Json转换,读取,写入

    using Newtonsoft.Json;using Newtonsoft.Json.Converters; //把Json字符串反序列化为对象目标对象 = JsonConvert.Deserial ...

  3. ComboBox智能搜索功能

    cmbList.AutoCompleteSource = AutoCompleteSource.ListItems; cmbList.AutoCompleteMode = AutoCompleteMo ...

  4. Delphi控件备份工具

    用途: 1.如果您需要重装Delphi,想省去重装控件的麻烦. 2.如果您把Delphi环境安装至另一台电脑上. 那么,您一定需要这个! 运行批处理后,自动在当前目录下生成备份目录. 批处理代码 @e ...

  5. 导入wordpress数据库到mysql报错

    mysql字符集编码错误的导入数据会提示错误了,这个和插入数据一样如果保存的数据与mysql编码不一样那么肯定会出现导入乱码或插入数据丢失的问题,下面我们一起来看一个例子. 恢复数据库报错:由于字符集 ...

  6. Java堆外内存之五:堆外内存管理类ByteBuffer

    本篇主要讲解如何使用直接内存(堆外内存),并按照下面的步骤进行说明: 相关背景-->读写操作-->关键属性-->读写实践-->扩展-->参考说明 希望对想使用直接内存的朋 ...

  7. 退出循环break,在while、for、do...while、循环中使用break语句退出当前循环,直接执行后面的代码。

    在while.for.do...while循环中使用break语句退出当前循环,直接执行后面的代码. 格式如下: for(初始条件;判断条件;循环后条件值更新) { if(特殊情况) {break;} ...

  8. 未知行数的文字在div中垂直居中

    今天工作中遇到一个问题,就是未知行数的文字在div中怎么垂直居中,如下面的3个图: 图1 图2 图3 图1是2行文字的效果,图2是不经过css垂直居中处理的效果,图3是经过css垂直居中后的效果,ht ...

  9. 取得 Ajax 返回参数

    ajax 函数,p1 为正常参数 function ExecWebFunction(callback,p1) { $.ajax({ type: "POST", contentTyp ...

  10. 安装phoenix时,执行命令./sqlline.py hostname1,hostname2.hostname3..... 时报错 ImportError: No module named argparse

    问题描述: 怎么解决呢: 网上看了好多方法,但是本屌丝表示看不懂啊,没理解人家的博客的博大精深,好吧我们回到正题!! 先切换到root用户下安装这个东西  yum  install  python-a ...