C# Aggregate 累加器

C# Aggregate 累加器

累加器是什麼?累加器怎麼用?別急,一項新技術的誕生,基本都是為了滿足某種需求,從需求出發,更容易理解這個函數的特點。

最後更新 2022/4/20 上午7:11
遇水寒
預計閱讀 5 分鐘
分類
.NET
標籤
.NET C# Aggregate

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 值。

實際使用:當資料庫中一張表參照了多張表的外部索引鍵,當需要查詢這些外部索引鍵的時候,就可以使用累加器,把需要查詢的條件累加起來,向資料庫進行查詢。

繼續探索

延伸閱讀

更多文章
同分類 / 同標籤 2026/2/7

AOT使用經驗總結

從專案建立伊始,就應養成良好的習慣,即只要添加了新功能或使用了較新的語法,就及時進行 AOT 發布測試。

繼續閱讀