C#编程,Linq累加器函数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扩展可以实现整个句子的倒序输出:

在这里插入图片描述

Aggregate还可以实现异或(^)操作:

public static void Test4()
{
    byte[] data = new byte[] { 0x31, 0x32, 0x33, 0x34, 0x35 };
    byte checkSum = data.Aggregate((a, n) => (byte)(a ^ n));
}

对经常作串口通信的朋友比较实用。

Aggregate

这个就是我们久久未引入的话题,利用它我们完全可以写出如Ruby一样优美的代码,我们来看看是如何求出1到100的和的:

        var list = Enumerable.Range(1, 100);
        var result = list.Aggregate((a, b) => (a + b));
        Console.WriteLine(string.Format("1到100的和为{0}", result));

就是这么easy,让我眼前一亮,对C#又充满了信心,正如上述而言,作为有工作经验的人,可能这个方法确实没有怎么用过,用的大多数是常见的Linq,当然了那么多Linq哪能全部都会用啊,但是,但是至少得了解这个Linq是做什么的吧(别往心里去,说的没见识的我)。

用法
该Linq字面意思为聚合,例如可用来对集合进行筛选以及上述的求和等等,它有三个重载,它是对列表上的每个元素执行操作,也就是说对第一个和第二个上的元素执行操作,将执行的结果继续携带进行操作。其中有一个重载是种子重载。

种子重载(Seed Overload)
我们求1到5的阶乘。

        var nums = Enumerable.Range(2, 4);
        var sum = nums.Aggregate(1, (a, b) => a * b);
        Console.WriteLine(sum);

所谓种子,也就是先从种子开始作为第一个元素执行操作,整个过程为((((1*2)*3)*4)*5)。

结语
本来没怎么接触过Aggregate,在项目中看到别人写到这么一段代码才让我下意识的知道对这个Linq完全没接触过,于是就有这一部分内容。在项目中有这样一个场景:打开对话框上传文件,可以对该文件进行命名,但是我们知道文件名是无法以某些特殊字符命名的如<或者|等等,当文件名为这些时,上传到后台我们会进行替换处理用“-”来进行替换。我们看看代码,例如:

        var invalidFileName = Path.GetInvalidFileNameChars();
        var replaceResult = invalidFileName.Aggregate("study<Aggregate>first", (accmulate, result) => (accmulate.Replace(result, '-')));
        Console.WriteLine(replaceResult);

结果如下:

Aggregate学习完毕,Sleep now!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值