GroupBy 將扁平序列轉換為分組序列 (IEnumerable<IGrouping<TKey, TElement>>),對應 SQL GROUP BY。本文詳細解析參數組合、延續查詢、複合鍵、自訂比較器與 LINQ to SQL 特有優化。
IEnumerable> GroupBy(
this IEnumerable source,
Func keySelector, // 必填:分組鍵
Func elementSelector, // 選填:分組內元素投影
IEqualityComparer comparer // 選填:鍵比較邏輯
)
string[] files = Directory.GetFiles(@"c:\temp");
var query = files.GroupBy(f => Path.GetExtension(f));
// 列舉結果
foreach (var group in query) {
Console.WriteLine("Extension: " + group.Key);
foreach (var file in group) Console.WriteLine(" - " + file);
}
// 將檔名轉大寫,分組鍵仍為副檔名
var query = files.GroupBy(
f => Path.GetExtension(f), // keySelector
f => f.ToUpper() // elementSelector
);
// 分組結果鍵相同,但元素為大寫檔名
注意: elementSelector 與 keySelector 獨立,不影響分組邏輯。
GroupBy **不保證** 分組順序,僅保留原序列中首次出現鍵的相對順序。需排序請顯式 OrderBy:
var sorted = files
.GroupBy(f => Path.GetExtension(f), f => f.ToUpper())
.OrderBy(g => g.Key); // 依副檔名排序
// 基本分組 (以 group 結尾)
var q1 = from f in files
group f.ToUpper() by Path.GetExtension(f);
// 延續查詢 (group ... into):後續可接 where/orderby/select
var q2 = from f in files
group f.ToUpper() by Path.GetExtension(f) into g
where g.Count() < 5 // 篩選分組
orderby g.Key
select g;
// 僅需聚合結果 (丟棄子序列)
string[] votes = { "Bush", "Gore", "Gore", "Bush", "Bush" };
var winner = (from v in votes
group v by v into g
orderby g.Count() descending
select g.Key).First(); // "Bush"
使用**匿名型別**建立複合鍵,編譯器自動實作 Equals/GetHashCode:
// 依首字母 + 長度 分組
var q = from n in names
group n by new { FirstLetter = n[0], Length = n.Length };
僅限 LINQ to Objects (本地查詢)。通常調整 keySelector 即可 (如 ToUpper()),極少需自訂 IEqualityComparer:
// 不區分大小寫分組 (等效於 keySelector: n => n.ToUpper())
var q = names.GroupBy(n => n, StringComparer.CurrentCultureIgnoreCase);
若實體間有**導航屬性** (關聯),往往不需要顯式 GroupBy:
// 找出訂單數 >= 2 的客戶 (利用導航屬性 Purchases)
var q = from c in ctx.Customers
where c.Purchases.Count >= 2
select c.Name + " has made " + c.Purchases.Count + " purchases";
// 年度銷售總額 (需 GroupBy)
var q = from p in ctx.Purchases
group p.Price by p.Date.Year into salesByYear
select new { Year = salesByYear.Key, TotalValue = salesByYear.Sum() };
善用導航屬性可簡化查詢,但彙總統計 (如年度總額) 仍需 GroupBy。