聚合方法
主要方法:
Count, LongCount: 返回輸入序列的元素數量, 並且滿足一個斷言(可選), SQL對應語法為COUNT()
Min, Max: 返回輸入序列中的最小或最大的元素, SQL對應語法為MIN(), MAX()
Sum, Average: 計算序列中的所有元素的總和或者平均數, SQL對應語法為SUM(), AVG()
Aggregate: 執行一個自定義的聚合計算, 無對應SQL語法
Count, LongCount
源序列: IEnumerable
斷言: TSource => bool (可選)
Count枚舉一個序列並返回其中的元素總數:
1: int fullCount = new int[] { 5, 6, 7}.Count(); // 3
在IEnumerable.Count的內部實現中, 它首先測試輸入序列是否實現了ICollection, 如果是, 則直接調用ICollection.Count, 否則就利用一個簡單的計算數遍歷所有元素每次加1獲得最後的總數.
另外, 我們也可以在查詢中提供一個斷言:
1: int digitCount = “jame921″.Count (c => char.IsDigit (c)); // 3
LongCount跟Count做一樣的工作, 只不過它返回的是一個64位的整數, 可以計算超過20億的元素
Min和Max
源序列: IEnumerable
可選結果選擇器: TSource => TResult
Min和Max分別返回輸入序列中最小和最大的元素:
1: int[] numbers = { 28, 32, 14 }; 2: 3: int smallest = numbers.Min(); // 14; 4: 5: int largest = numbers.Max(); // 32;
你也可以包含一個選擇表達式:
1: int smallest = numbers.Max (n => n % 10); // 8;
如果元素本身並不是可比較的, 那麼選擇器表達式就是必須的了, 換句話說, 如果元素沒有實現IComparable, 例如:
1: Purchase runtimeError = 2: 3: dataContext.Purchases.Min(); // 編譯錯誤 4: 5: decimal? lowestPrice = 6: 7: dataContext.Purchases.Min (p => p.Price); // OK
一個選擇器表達式不僅決定元素之間如何做比較, 同時也可以影響最後的結果. 例如前面的例子返回的結果是一個decimal類型的數值, 而不是一個purchase對象, 為了要獲得最便宜的采購訂單, 我們需要一個子查詢:
1: Purchase cheapest = dataContext.Purchases 2: 3: .Where (p => p.Price == 4: 5: dataContext.Purchases.Min(p2 => p2.Price)) 6: 7: .FirstOrDefault();
Sum與Average
源序列: IEnumerable
可選的結果選擇器: TSource => TResult
Sum和Average這兩個聚合操作符使用與Min和Max類似:
1: decimal[] numbers = { 3, 4, 8 }; 2: 3: decimal sumTotal = numbers.Sum(); // 15 4: 5: average = numbers.Average(); // 5
以下查詢返回names數組中每一個元素的長度總和:
1: int combinedLength = names.Sum (s =>s.Length);
Sum和Average操作必需是關於數值類型(int, long, float, double以及nullable版本), 相反的, Min和Max就沒有這麼嚴格的限定, 它們可以操作那些實現了Icomparable的元素, 例如string. 此外, Average總是返回decimal或者double兩者之一:
1.如果選擇器類型是decimal,則返回類型也是decimal
2.如果選擇器類型是int, long, float, double, 則返回類型是double
這意味著下面的查詢無法編譯(因為double不能為自動轉換為int)
1: int avg = new int[] { 3, 4 }.Average();
但是以下的查詢則沒有問題:
1: double avg = new int[] { 3, 4}.Average(); // 3.5
Average隱式提高輸入值的精度以避免原有精度丟失. 這這個例子中, 我們取得平均值3.5, 而不需要去訴求於一個輸入元素的轉換:
1: double avg = numbers.Average (n =>(double) n);
在LINQ to SQL中, Sum和Average被翻譯成了標准的SQL聚合函數, 以下的查詢返回了那些包含有訂單平均值 > 500的客戶名稱:
1: from c in dataContext.Customers 2: 3: where c.Purchases.Average (p => p.Price) > 500 4: 5: select c.Name;
聚合
Aggregate允許你嵌入一個自定義的算法來實現那些不是很常用的聚合場景. Aggregations在LINQ to SQL當中不受支持. 以下的查詢演示了如果使用Aggregate來做與Sum的工作:
1: int[] numbers = { 1, 2, 3 }; 2: int sum = numbers.Aggregate (0, (seed, n)=> seed + n);
第一個參數是seed,表示從那個元素位置開始計算. 第二個參數是一個更新計算結果值的表達式, 並作為一個新的元素繼續循環下去. 我們還可以使用可選的第三個參數在返回值的時候再作進一步的project. 待續!