LINQ中的Aggregate
方法执行一个累计操作。Aggregate
扩展方法有以下重载方法:
public static TSource Aggregate<TSource>(this IEnumerable<TSource> source,
Func<TSource, TSource, TSource> func);
public static TAccumulate Aggregate<TSource, TAccumulate>(this IEnumerable<TSource> source,
TAccumulate seed,
Func<TAccumulate, TSource, TAccumulate> func);
public static TResult Aggregate<TSource, TAccumulate, TResult>(this IEnumerable<TSource> source,
TAccumulate seed,
Func<TAccumulate, TSource, TAccumulate> func,
Func<TAccumulate, TResult> resultSelector);
下面我们以具体的示例来一步一步学习LINQ的Aggregate
聚合操作符。
比如有如下的数字类型的数组:
var numbers = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
现要求对数组numbers
进行求和(用C#语言实现),你会想到的做法是什么呢?
传统的循环遍历方式
在没有学习LINQ的聚合操作符之前,我们通常的做法可能是循环遍历的方式来实现上述的需求,示例代码如下:
using System;
namespace LinqTutorial
{
public class MyProgram
{
static void Main(string[] args)
{
var numbers = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var sum = 0;
for (var i = 0; i < numbers.Length; i++)
{
sum += numbers[i];
}
Console.WriteLine(sum);
Console.Read();
}
}
}
运行得到的求和结果为:45
LINQ的Aggregate聚合
以上使用统计的循环遍历实现得到的最终结果是没有问题的,但过程相当繁琐。这样的场景,我们可以借助.NET内置的Aggregate
聚合操作符进行求和计算,示例代码如下:
using System;
using System.Linq;
namespace LinqTutorial
{
public class MyProgram
{
static void Main(string[] args)
{
var numbers = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var sum = numbers.Aggregate((num, i) => num + i);
Console.WriteLine(sum);
Console.Read();
}
}
}
可以看到,使用Aggregate
聚合操作符仅一行代码就实现了循环遍历的工作,无疑可以提高开发者的生产效率。
这也是C#语言优雅语法的真正体现:用更少的、更优美的代码,实现相同的功能需求。
读到这里,我可能对Aggregate
聚合操作符还是一头雾水。没关系,下面我们按照Aggregate
的执行步骤对上例一步一步进行分解。
示例代码中,Aggregate
聚合方法中的lambda表达式(num, i) => num + i
在执行时可以表达到这样的: num = num + i
,其中num
将作为数组中的每个项的累积。
因此,Aggregate
方法将返回数组的累加和。下面请看累加操作是如何一步步执行的:
- 第1步,将
numbers
集合中的第一个元素(1
)赋值给num
,第二个元素2
赋值给i
,进行表达式num + i
的运算,并将运算得到的结果(1+2=3)返回。 - 第2步,将上一步得到的结果再次赋值给
num
,numbers
集合的下次迭代元素3
(这里应该是第2次迭代)赋值给i
,进行表达式num + i
的运算,将运算得到的结果(3+3=6)返回。 - 以次类推,直到把
numbers
集合的元素迭代完为止,最后返回所有元素累加的结果。
为了方便直观查看Aggregate
方法的变量,我们在Aggregate
方法中添加变量的输出日志,示例如下:
using System;
using System.Linq;
namespace LinqTutorial
{
public class MyProgram
{
static void Main(string[] args)
{
var numbers = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var sum = numbers.Aggregate((num, i) =>
{
var val = num + i;
Console.WriteLine($"num({num}) + i({i}) = {val}");
return val;
});
Console.WriteLine(sum);
Console.Read();
}
}
}
输出结果如下:
有种子参数的Aggregate重载方法
Aggregate
方法的第二个重载是将第一个参数作为要累积的种子值,第二个参数是Func类型的委托(delegate),还是以上面做1到9的累加求和为例,只是这里使用有种参数的重载方法,语法示例如下:
var sum = numbers.Aggregate(2, (num, i) => num + i);
为了方便观察Aggregate
方法的执行过程,同样的,我们将变量输出到了控制台。完整示例如下:
using System;
using System.Linq;
namespace LinqTutorial
{
public class MyProgram
{
static void Main(string[] args)
{
var numbers = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var sum = numbers.Aggregate(2, (num, i) =>
{
var val = num + i;
Console.WriteLine($"num({num}) + i({i}) = {val}");
return val;
});
Console.WriteLine(sum);
Console.Read();
}
}
}
运行结果如下:
从运行结果可以看出,有种子参数的Aggregate
方法重载比没有的多执行了一次,即第1次:num(2) + i(1) = 3
。也就是说,如果有种子值,则Aggregate
方法将在执行第1次迭代时使用种子值,之后再依次迭代集合的每个元素。
Aggregate拼接字符串
当然,Aggregate
扩展方法不止能做数学运算,也可以处理字符,比如字符串的拼接问题,示例如下:
using System;
using System.Linq;
namespace LinqTutorial
{
public class MyProgram
{
static void Main(string[] args)
{
var numbers = new[] { "One", "Two", "Three", "Four", "Five" };
var result = numbers.Aggregate((current, index) => current + "," + index);
Console.WriteLine(result);
Console.Read();
}
}
}
运行结果:
One,Two,Three,Four,Five
除了正序拼接字符串,还可以反序拼接字符串,示例代码如下:
var result = numbers.Aggregate((current, index) => index + "," + current);
提示:你看出正序和反序拼接字符串实现方式的区别了吗?
运行结果:
Five,Four,Three,Two,One
Aggregate的结果选择器参数
Aggregate方法的第3个重载需要结果选择器的Func
委托表达式的作为第三个形参,以便对聚合的结果进行进一步的处理,这里还是以将字符串集合拼接成以逗号隔开的字符串为例,示例代码如下:
using System;
using System.Linq;
namespace LinqTutorial
{
public class MyProgram
{
static void Main(string[] args)
{
var numbers = new[] { "One", "Two", "Three", "Four", "Five" };
var result = numbers.Aggregate("", (current, index) => current + "," + index);
Console.WriteLine(result);
Console.Read();
}
}
}
运行的结果:
,One,Two,Three,Four,Five
注:因为第1个参数的种子值是空字符串,所以拼接出来的结果以逗号开头。
现在,我们借助Aggregate
的第3个参数,对结果进行处理,即去掉开头多余的逗号,示例如下:
using System;
using System.Linq;
namespace LinqTutorial
{
public class MyProgram
{
static void Main(string[] args)
{
var numbers = new[] { "One", "Two", "Three", "Four", "Five" };
var result = numbers.Aggregate("",
(current, index) => current + "," + index
, str => str.TrimStart(','));
Console.WriteLine(result);
Console.Read();
}
}
}
运行结果:
One,Two,Three,Four,Five
Aggregate总结
本文详细介绍了LINQ中Aggregate聚合方法及重载的不同场景的使用方法。希望以上内容能对你的Aggregate学习带来一些启发和帮助。
发表评论
登录用户才能发表评论, 请 登 录 或者 注册