iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 28
0
Software Development

深入探索LINQ系列 第 28

C#的利器LINQ-Aggregate的應用

這次要說的Aggregate這個方法是在做彙整的處理,彙整資料之後可以幫我們找出很多本來看不清的數據,所以Aggregate這個方法的用法及實作也是很重要的,我們一起來看看吧。

功能說明

以下圖為例(節錄自Microsoft Docs):

https://ithelp.ithome.com.tw/upload/images/20180116/20107789Oi8cqGHp2y.png

以下說明圖片:

  • Source是一個數字陣列
  • Results有兩種: SumMax
    • Sum: 加總Source的元素數值
    • Max: Source元素數值的最大值

由圖示我們可以知道Aggregate會對一個集合的內容整理後輸出成一個資料。

方法定義

Aggregate三個公開方法,我們由單純到複雜來說明:

第一個方法

public static TSource Aggregate<TSource>(
    this IEnumerable<TSource> source,
    Func<TSource, TSource, TSource> func);
  • func: 彙整資料所做的處理函式
  • func第一個傳入參數: 之前元素的彙整結果
  • func第二個傳入參數: 目前元素的資料
  • func的回傳值: 之前元素跟目前元素的彙整結果

由此可以看出來Aggregate這個方法其實就是把之前元素的彙整資料跟目前的元素做彙整,再將目前彙整的結果丟到下一個元素再做彙整,最後就會得到一個彙整的結果。

第二個方法

public static TAccumulate Aggregate<TSource, TAccumulate>(
    this IEnumerable<TSource> source,
    TAccumulate seed,
    Func<TAccumulate, TSource, TAccumulate> func);
  • seed: 初始的累加值
  • func: 彙整資料所做的處理函式

這個方法多了一個seed參數,他是自定義的初始值,這個值會傳入func中,變為第一個func的傳入參數,以用來做彙整。

第三個方法

public static TResult Aggregate<TSource, TAccumulate, TResult>(
    this IEnumerable<TSource> source,
    TAccumulate seed,
    Func<TAccumulate, TSource, TAccumulate> func,
    Func<TAccumulate, TResult> resultSelector);

這個方法跟上一個方法的差別只有resultSelector這個參數,他會在巡覽結束得到彙整資料的時候去叫用resultSelector去產生結果。

方法範例

這次的範例我們會用Aggregate來實作不同的彙整處理(AverageCountMaxMinSum),範例中會有一行註解程式碼,它的結果跟我們輸出的結果相同。

範例資料

int[] Source = new int[] { 2, 7, 5, 1, 6, 8, 3 };

Sum

private static int Sum(IEnumerable<int> source)
{
    //return source.Sum(x => x);
    return source.Aggregate((total, next) => total + next);
}

total會是之前所有元素的加總,所以每次叫用func時都是在加上目前的數字

Min

private static int Min(IEnumerable<int> source)
{
    //return source.Min(x => x);
    return source.Aggregate((min, next) => min > next ? next : min);
}

每次都去比對目前的元素是否小於目前的最小值,如果是的話就更新最小值。

Max

private static int Max(IEnumerable<int> source)
{
    //return source.Max(x => x);
    return source.Aggregate((max, next) => max < next ? next : max);
}

每次都去比對目前的元素是否大於目前的最大值,如果是的話就更新最大值。

Count

private static int Count(IEnumerable<int> source)
{
    //return source.Count();
    return source.Aggregate(0, (count, next) => ++count);
}

0為起始彙整資料,每個元素都累加1

Average

private static double Average(IEnumerable<int> source)
{
    int count = 0;

    //return source.Average(x => x);
    return source.Aggregate(
        0,
        (total, next) =>
        {
            total = total + next;
            count++;
            return total;
        },
        total => (double)total / count
    );
}

累加元素並對外部變數count1,最後用resultSelector取得平均資料。

範例的結果如下:

/*
 * Source: 2,7,5,1,6,8,3
 *  Average: 4.57142857142857
 *  Count: 7
 *  Max: 8
 *  Min: 1
 *  Sum: 32
 */

特別之處

  • 沒有延遲執行的特性,一旦叫用會馬上觸發

結語

這次的Aggregate只要了解func中兩個傳入參數: 累加值目前元素值就可以理解他的運用方法了,搭配不同的彙整處理的例子又更加的明確,下一章我們來看看Aggregate的原理。

範例程式

參考


上一篇
C#的利器LINQ-Take的原碼探索
下一篇
C#的利器LINQ-Aggregate的原碼探索
系列文
深入探索LINQ30

尚未有邦友留言

立即登入留言