1. 需求
累加器是什麼?累加器怎麼用?別急,一項新技術的誕生,基本都是為了滿足某種需求,從需求出發,更容易理解這個函數的特點。
為方便理解,假設有一個 int 一維數組,儲存 5 個數字,求出第一個值(-1)加上第二個值(0)的和(-1),再將求得的值(-1)和數組的第三個數(3)相加,再次求和(2),再次將該值和數組的第四個數(5)相加。。。以此類推,得出其實就是:int result = -1 + 0 + 3 + 5 + 8;
int[] numbers={-1, 0, 3, 5,8};
1.1基本需求
//V1.0版本
static void Main(string[] args)
{
int[] numbers = { -1, 0, 3, 5, 8 };
int result = numbers[0];
for (int i = 1; i < numbers.Length; i++)
{
result = result + numbers[i];
}
Console.WriteLine(result);//输出15
Console.ReadKey();
}
1.2封裝算法部分
把中間的算法提取出來,這樣可以輸入其他不同長度的 int 類型數組了:
//V1.1 版本
static void Main(string[] args)
{
int[] numbers = { -1, 0, 3, 5, 8 };
var result = Aggregate(numbers);
Console.WriteLine(result);
Console.ReadKey();
}
static int Aggregate(int[] array)
{
int result = array[0];
for (int i = 1; i < array.Length; i++)
{
result = result + array[i];
}
return result;
}
1.3不只是實現加法–算法替換
累加器要做到不是只能做加法,例如:
int result = -1 * 0 * 3 * 5 * 8;
int result = -1 - 0 - 3 - 5 - 8;
//V1.2 版本,实现算法替换
//需了解委托,Lambda相关知识
static void Main(string[] args)
{
int[] numbers = { -1, 0, 3, 5, 8 };
var result = Aggregate(numbers,(result,next)=>result * next);//实现乘法
//var result = Aggregate(numbers,(result,next)=>result - next);//实现减法
Console.WriteLine(result);
Console.ReadKey();
}
static int Aggregate(int[] array,Func<int,int,int> func)
{
int result = array[0];
for (int i = 1; i < array.Length; i++)
{
result = func(result, array[i]);
}
return result;
}
1.4不只是 int 類型–泛型
目前该算法int Aggregate(int[] array,Func<int,int,int> func)只支持 int 类型,现在要扩展到任意类型–泛型。
//V1.3 版本,实现泛型
//需了解泛型,IEnumerator接口相关知识
static void Main(string[] args)
{
int[] numbers = { -1, 0, 3, 5, 8 };
var result = Aggregate(numbers, (result, next) => result + next);
Console.WriteLine(result);
Console.ReadKey();
}
static TSource Aggregate<TSource>(IEnumerable<TSource> source,Func<TSource, TSource, TSource> func)
{
using (IEnumerator<TSource> e = source.GetEnumerator())
{
if (!e.MoveNext())
{
throw new ArgumentException();
}
TSource result = e.Current;
while (e.MoveNext())
{
result = func(result, e.Current);
}
return result;
}
}
1.5實現方式變成拓展方法
直接對實現了 ienumerator 接口的類,添加擴展方法。至此,該 aggregate 實現的功能已經和官網提供的累加器相似了。
//V1.4 版本,扩展方法
class Program
{
static void Main(string[] args)
{
int[] numbers = { -1, 0, 3, 5, 8 };
var result = numbers.Aggregate((result, next) => result + next);
Console.WriteLine(result);
Console.ReadKey();
}
}
public static class Helper
{
public static TSource Aggregate<TSource>(this IEnumerable<TSource> source, Func<TSource, TSource, TSource> func)
{
using (IEnumerator<TSource> e = source.GetEnumerator())
{
if (!e.MoveNext())
{
throw new ArgumentException("需要至少两个元素");
}
TSource result = e.Current;
while (e.MoveNext())
{
result = func(result, e.Current);
}
return result;
}
}
}
2. 微軟提供的 api
在 system.linq 命名空間下,提供了:
1. public static TSource Aggregate<TSource>(this IEnumerable<TSource> source, Func<TSource, TSource, TSource> func);
2. public static TAccumulate Aggregate<TSource, TAccumulate>(this IEnumerable<TSource> source, TAccumulate seed, Func<TAccumulate, TSource, TAccumulate> func);
3. public static TResult Aggregate<TSource, TAccumulate, TResult>(this IEnumerable<TSource> source, TAccumulate seed, Func<TAccumulate, TSource, TAccumulate> func, Func<TAccumulate, TResult> resultSelector);
其中第一個接口,與我上述舉例的功能一樣。其他兩個功能放後面講解(有時間的話)。
3.由淺入深
如果是初学者,可能大脑第一反应还是觉得这个Aggregate只能加减乘除,如果这样想,说明其实还是理解得不够深刻,现在来深度剖析该方法的传参:func。
如下圖所示,累加器會遍歷每一個元素,除了第一次,是直接拿第一和第二個元素進行 func 運算之外,從第三個開始,都是拿上一次的計算結果 result 作為 func 的第一個輸入參數,第二個輸入參數為數組的下一個元素,直到遍歷到最後,返回一個最終的 result 值。
實際使用:當資料庫中一張表引用了多張表的外鍵,當需要查詢這些外鍵的時候,就可以使用累加器,把需要查詢的條件累加起來,向資料庫進行查詢。
