首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# 擴展方法進階實戰:Aggregate 聚合運算深度解析與改良

     編輯:關於C#

前言

Enumerable.Aggregate 是 LINQ 中最基礎也最強大的聚合運算,其他聚合方法 (Sum, Max, Min, Average) 皆可視為其特例。本文解析其運作原理、進階應用,並改良加入索引參數擴展功能。

基本語法與範例

// 基本求和 (不如 Sum 直觀)
int sum = nums.Aggregate((a, b) => a + b);

// 字串串接
string sentence = words.Aggregate((a, b) => a + " " + b);

// 異或校驗和 (串口通訊常用)
byte checksum = data.Aggregate((a, b) => (byte)(a ^ b));

內部實現原理

// 簡化版來源碼
public static TSource Aggregate<TSource>(
    this IEnumerable<TSource> source, 
    Func<TSource, TSource, TSource> func)
{
    using var enumerator = source.GetEnumerator();
    if (!enumerator.MoveNext()) throw new InvalidOperationException("序列為空");
    
    TSource result = enumerator.Current;
    while (enumerator.MoveNext())
        result = func(result, enumerator.Current);
    
    return result;
}

參數對應:func(累積值, 當前元素) → 回傳新累積值。

進階應用場景

1. 字串反轉累積


string reverse = words.Aggregate((a, b) => b.Reverse() + " " + a);
// 需自訂 Reverse 擴展
public static string Reverse(this string s) 
    => new string(s.Reverse().ToArray());

2. 尋找重複數字 (極限算法)


// 1~n 放入 n+1 長度陣列,唯一重複,找出重複數
int[] arr = { 1, 3, 2, 3, 4, 5 };

// 原版:Select + Sum
int dup1 = arr.Select((val, idx) => val - idx).Sum(); // 3

// 改良版:單一 Aggregate
int dup2 = arr.Aggregate((acc, val, idx) => acc + val - idx); // 3

改良版:加入索引參數的 Aggregate


public static class AggregateExtensions
{
    // 多載 1: 累積值、當前元素、索引 (從 0 開始)
    public static TSource Aggregate<TSource>(
        this IEnumerable<TSource> source,
        Func<TSource, TSource, int, TSource> func)
    {
        int index = 0;
        using var enumerator = source.GetEnumerator();
        if (!enumerator.MoveNext()) throw new InvalidOperationException("序列為空");
        
        TSource result = enumerator.Current;
        index++;
        while (enumerator.MoveNext())
            result = func(result, enumerator.Current, index++);
        
        return result;
    }

    // 多載 2: 指定種子值、累積值、當前元素、索引
    public static TAccumulate Aggregate<TSource, TAccumulate>(
        this IEnumerable<TSource> source,
        TAccumulate seed,
        Func<TAccumulate, TSource, int, TAccumulate> func)
    {
        int index = 0;
        TAccumulate result = seed;
        foreach (var item in source)
            result = func(result, item, index++);
        return result;
    }

    // 多載 3: 完整版 (種子、累積函式、結果選擇器、索引)
    public static TResult Aggregate<TSource, TAccumulate, TResult>(
        this IEnumerable<TSource> source,
        TAccumulate seed,
        Func<TAccumulate, TSource, int, TAccumulate> func,
        Func<TAccumulate, TResult> resultSelector)
    {
        return resultSelector(source.Aggregate(seed, func));
    }
}

改良版應用範例


// 間隔求和:索引為偶數的元素相加 (0, 2, 4...)
int[] nums = { 10, 20, 30, 40, 50 };
int evenSum = nums.Aggregate((acc, val, idx) => acc + (idx % 2 == 0 ? val : 0)); // 10+30+50=90

// 計算加權平均
var weightedAvg = items.Aggregate(
    (Sum: 0.0, Weight: 0.0), 
    (acc, item, idx) => (acc.Sum + item.Value * item.Weight, acc.Weight + item.Weight),
    acc => acc.Sum / acc.Weight);

// 字串插值建構
string csv = items.Aggregate(
    "", 
    (acc, item, idx) => acc + (idx > 0 ? "," : "") + item.Name);

效能與使用建議

場景建議
簡單求和/最大/最小/平均直接用 Sum/Max/Min/Average (可讀性最佳)
字串串接用 string.Join 或 StringBuilder (效能優於 Aggregate)
複雜累積邏輯需索引使用改良版 Aggregate
多欄位累積使用 Tuple/ValueTuple 作為種子值
空序列處理使用帶種子值的多載避免例外

結語

Aggregate 是函數式聚合的核心構建塊。理解其運作機制、善用種子值與索引參數,能以極簡代碼表達複雜聚合邏輯。改良版擴展方法填補了原生 API 缺乏索引參數的缺口,推薦收納於專案工具庫中。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved