總目錄
前言
在 C# 中,System.Linq.Enumerable 類是 LINQ(Language Integrated Query)的核心組成部分,它提供了一系列靜態方法,用于操作實現了 IEnumerable 接口的集合。通過這些方法,我們可以輕松地對集合進行查詢、轉換、排序和聚合等操作。
本文屬于 C# Enumerable類 使用詳解 中的一個章節,著重介紹 C# Enumerable 類中數據分組這部分的內容。
一、概覽
方法 | 描述 | 示例 |
---|---|---|
GroupBy | 數據分組 | people.GroupBy(p => p.Age); |
ToLookup | 數據分組 | people.ToLookup(p => p.Age); |
二、GroupBy
:數據分組
1. 什么是 GroupBy
GroupBy
是 LINQ 提供的一個擴展方法,用于將源集合中的元素按某個鍵值進行分組,并返回一個包含 IGrouping<TKey, TElement>
對象的集合。每個 IGrouping<TKey, TElement>
對象都表示一個組,其中包含該組的鍵和屬于該組的所有元素。
2. GroupBy 方法 基本信息
GroupBy
方法用于根據指定的鍵對集合中的元素進行分組。
1) GroupBy
public static IEnumerable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey>(this IEnumerable<TSource> source,Func<TSource, TKey> keySelector)public static IEnumerable<IGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>(this IEnumerable<TSource> source,Func<TSource, TKey> keySelector,Func<TSource, TElement> elementSelector)public static IEnumerable<TResult> GroupBy<TSource, TKey, TResult>(this IEnumerable<TSource> source,Func<TSource, TKey> keySelector,Func<TKey, IEnumerable<TSource>, TResult> resultSelector)
-
參數:
-
source:要分組的源集合。
-
keySelector:一個函數,用于從源集合的每個元素中提取分組鍵。
-
elementSelector(可選):一個函數,用于從源集合的每個元素中選擇要包含在組中的元素。
- 指定組內元素的映射方式(默認映射原元素)
-
resultSelector(可選):一個函數,用于定義如何將每個組轉換為最終結果。
- 自定義分組結果的輸出格式
-
-
返回值:
GroupBy
方法返回一個IEnumerable<IGrouping<TKey, TElement>>
集合,其中:- TKey:表示分組依據的鍵類型。
- TElement:表示原始集合中的元素類型。
2)工作原理
-
迭代源集合
GroupBy 方法首先會迭代源集合中的每一個元素。對于每個元素,它會調用 keySelector 函數來提取分組鍵。 -
創建組
根據提取的鍵值,GroupBy 方法會創建或找到相應的組。如果某個鍵值對應的組已經存在,則將當前元素添加到該組中;如果不存在,則創建一個新的組并將當前元素添加進去。 -
返回結果
在遍歷完所有元素后,GroupBy 方法返回一個包含所有組的集合。每個組都是一個 IGrouping<TKey, TElement> 對象,包含了鍵值和該組的所有元素。 -
惰性求值
GroupBy 方法采用惰性求值(Lazy Evaluation),這意味著它不會立即執行分組操作,而是等到實際遍歷時才進行計算。這使得 GroupBy 可以處理無限序列或延遲執行復雜的查詢。
3)使用場景
- 數據分類:當需要根據某個屬性或多個屬性對數據進行分類時。
- 數據統計:當需要計算每個類別的統計信息(如計數、總和、平均值等)時。
- 復雜的查詢和分析:當需要對數據進行復雜的查詢和分析時。
3. 使用示例
示例 1:基本分組
假設我們有一個包含若干 Person
對象的列表,每個對象都有 Name
和 Age
屬性。我們希望根據 Age
屬性對這些對象進行分組。
class Person
{public string Name { get; set; }public int Age { get; set; }public override string ToString(){return $"{Name} ({Age})";}
}class Program
{static void Main(){List<Person> people = new List<Person>{new Person { Name = "Alice", Age = 30 },new Person { Name = "Bob", Age = 25 },new Person { Name = "Charlie", Age = 30 },new Person { Name = "David", Age = 25 }};var groupedPeople = people.GroupBy(p => p.Age);foreach (var group in groupedPeople){Console.WriteLine($"Age: {group.Key}");foreach (var person in group){Console.WriteLine($" {person}");}}}
}
輸出結果:
Age: 30Alice (30)Charlie (30)
Age: 25Bob (25)David (25)
在這個例子中,我們使用 GroupBy
方法根據 Age
屬性對 people
列表進行了分組,并打印了每個組及其成員。
示例 2:選擇特定元素
有時我們只關心某些特定的屬性,而不是整個對象。在這種情況下,可以使用 elementSelector
參數來選擇要包含在組中的元素。
var groupedNames = people.GroupBy(p => p.Age, p => p.Name);foreach (var group in groupedNames)
{Console.WriteLine($"Age: {group.Key}");foreach (var name in group){Console.WriteLine($" {name}");}
}
輸出結果:
Age: 30AliceCharlie
Age: 25BobDavid
在這個例子中,我們只選擇了 Name
屬性進行分組,并打印了每個組的名稱。
示例 3:投影分組結果
我們可以使用 resultSelector
參數來自定義分組后的結果。例如,我們可以計算每個年齡段的人數。
var ageCounts = people.GroupBy(p => p.Age,(age, persons) => new { Age = age, Count = persons.Count() }
);foreach (var ageCount in ageCounts)
{Console.WriteLine($"Age: {ageCount.Age}, Count: {ageCount.Count}");
}
輸出結果:
Age: 30, Count: 2
Age: 25, Count: 2
在這個例子中,我們使用 resultSelector
參數創建了一個匿名對象,其中包含每個年齡段的人數。
示例 4:與其他LINQ方法結合
GroupBy
方法還可以與其他 LINQ 方法結合使用,以實現更復雜的數據處理。例如,我們可以使用 Select
方法來投影每個組的結果:
public class Student
{public string Name { get; set; }public int Grade { get; set; }
}public class Program
{public static void Main(){List<Student> students = new List<Student>{new Student { Name = "Alice", Grade = 10 },new Student { Name = "Bob", Grade = 11 },new Student { Name = "Charlie", Grade = 10 },new Student { Name = "David", Grade = 12 },new Student { Name = "Eve", Grade = 11 }};var summary = students.GroupBy(student => student.Grade).Select(group => new{Grade = group.Key,Count = group.Count(),Names = string.Join(", ", group.Select(s => s.Name))});foreach (var item in summary){Console.WriteLine($"Grade {item.Grade} has {item.Count} students: {item.Names}");}}
}
輸出結果:
Grade 10 has 2 students: Alice, Charlie
Grade 11 has 2 students: Bob, Eve
Grade 12 has 1 students: David
示例4 和 示例5 效果是一樣的,只不過示例4 是利用GroupBy
的一個重載方法實現,而示例5 是結合Select
方法實現的。
示例 5:多列分組
有時我們需要根據多個屬性進行分組。可以通過組合多個屬性來創建復合鍵。
var groupedByAgeAndName = people.GroupBy(p => new { p.Age, p.Name });foreach (var group in groupedByAgeAndName)
{Console.WriteLine($"Age: {group.Key.Age}, Name: {group.Key.Name}");foreach (var person in group){Console.WriteLine($" {person}");}
}
輸出結果:
Age: 30, Name: AliceAlice (30)
Age: 25, Name: BobBob (25)
Age: 30, Name: CharlieCharlie (30)
Age: 25, Name: DavidDavid (25)
在這個例子中,我們根據 Age
和 Name
屬性創建了一個復合鍵,并對 people
列表進行了分組。
示例 6:使用自定義比較器
默認情況下,GroupBy
方法使用默認的相等比較器來比較鍵。如果需要自定義比較邏輯,可以傳遞一個 IEqualityComparer<TKey>
實現。
class Person
{public string Name { get; set; }public int Age { get; set; }public override string ToString(){return $"{Name} ({Age})";}
}class CustomComparer : IEqualityComparer<int>
{public bool Equals(int x, int y){// 自定義比較邏輯:年齡相差不超過1歲視為相同return Math.Abs(x - y) <= 1;}public int GetHashCode(int obj){return obj.GetHashCode();}
}class Program
{static void Main(){List<Person> people = new List<Person>{new Person { Name = "Alice", Age = 30 },new Person { Name = "Bob", Age = 25 },new Person { Name = "Charlie", Age = 30 },new Person { Name = "David", Age = 26 }};// 使用自定義比較器進行分組var customGroupedPeople = people.GroupBy(p => p.Age, new CustomComparer());foreach (var group in customGroupedPeople){Console.WriteLine($"Age: {group.Key}");foreach (var person in group){Console.WriteLine($" {person}");}}}
}
輸出結果:
Age: 30Alice (30)Charlie (30)
Age: 25Bob (25)
Age: 26David (26)
在這個例子中,我們使用了一個自定義的比較器來分組年齡相差不超過1歲的人員。實際上并沒有生效。
示例 6:合并多個集合
有時我們需要合并多個集合并對合并后的結果進行分組。可以使用 Concat
或 Union
方法先合并集合,然后再使用 GroupBy
進行分組。
class Person
{public string Name { get; set; }public int Age { get; set; }public override string ToString(){return $"{Name} ({Age})";}
}class Program
{static void Main(){List<Person> people = new List<Person>{new Person { Name = "Alice", Age = 30 },new Person { Name = "Bob", Age = 25 }};List<Person> morePeople = new List<Person>{new Person { Name = "Charlie", Age = 30 },new Person { Name = "David", Age = 40 }};// 合并兩個集合var combinedPeople = people.Concat(morePeople);// 使用 GroupBy 對合并后的集合進行分組var groupedCombinedPeople = combinedPeople.GroupBy(p => p.Age);foreach (var group in groupedCombinedPeople){Console.WriteLine($"Age: {group.Key}");foreach (var person in group){Console.WriteLine($" {person}");}}}
}
輸出結果:
Age: 30Alice (30)Charlie (30)
Age: 25Bob (25)
Age: 40David (40)
4. 注意事項
GroupBy
方法是一個延遲執行的操作,這意味著它不會立即執行分組操作,而是直到結果被枚舉時才會執行。- 分組鍵必須是可比較的,否則會引發異常。
- 如果源集合為空,
GroupBy
方法將返回一個空的集合。
三、ToLookup
:數據分組
1. 什么是 ToLookup
ToLookup
是 LINQ 提供的一個擴展方法,用于根據指定的鍵對集合中的元素進行分組,并返回一個 ILookup<TKey, TElement>
對象。每個 ILookup<TKey, TElement>
對象都表示一個鍵到多個元素的映射。
2. ToLookup 方法 基本信息
ToLookup
方法用于根據指定的鍵對集合中的元素進行分組,并返回一個 ILookup<TKey, TElement>
對象。
1) ToLookup
ToLookup
方法有多種重載形式,以下是幾種常見的簽名:
public static ILookup<TKey, TSource> ToLookup<TSource, TKey>(this IEnumerable<TSource> source,Func<TSource, TKey> keySelector
)public static ILookup<TKey, TElement> ToLookup<TSource, TKey, TElement>(this IEnumerable<TSource> source,Func<TSource, TKey> keySelector,Func<TSource, TElement> elementSelector
)public static ILookup<TKey, TSource> ToLookup<TSource, TKey>(this IEnumerable<TSource> source,Func<TSource, TKey> keySelector,IEqualityComparer<TKey> comparer
)public static ILookup<TKey, TElement> ToLookup<TSource, TKey, TElement>(this IEnumerable<TSource> source,Func<TSource, TKey> keySelector,Func<TSource, TElement> elementSelector,IEqualityComparer<TKey> comparer
)
-
參數
- source:要轉換為
ILookup
的源集合。 - keySelector:一個函數,用于從源集合的每個元素中提取分組鍵。
- elementSelector(可選):一個函數,用于從源集合的每個元素中選擇要包含在組中的元素。
- comparer(可選):一個
IEqualityComparer<TKey>
實現,用于比較鍵值。
- source:要轉換為
-
返回類型:
ToLookup
方法返回一個ILookup<TKey, TElement>
集合,其中:- TKey:表示分組依據的鍵類型。
- TElement:表示原始集合中的元素類型。
- 每個
ILookup<TKey, TElement>
對象都包含一個鍵和屬于該鍵的所有元素。
2)工作原理
-
即時求值
與 GroupBy 的惰性求值不同,ToLookup 是立即執行的。這意味著它會立即遍歷整個源集合并構建結果。這使得 ToLookup 更適合需要頻繁查詢且希望避免重復執行分組操作的場景。 -
創建組
ToLookup 方法首先會迭代源集合中的每一個元素。對于每個元素,它會調用 keySelector 函數來提取分組鍵。然后根據提取的鍵值創建或找到相應的組。 -
添加元素
根據提取的鍵值,ToLookup 方法會將當前元素添加到對應的組中。如果某個鍵值對應的組已經存在,則將當前元素添加到該組中;如果不存在,則創建一個新的組并將當前元素添加進去。 -
返回結果
在遍歷完所有元素后,ToLookup 方法返回一個 ILookup<TKey, TElement> 對象,該對象包含了所有分組后的結果。由于 ILookup<TKey, TElement> 是只讀的,一旦創建就不能修改。 -
多次查詢
由于 ILookup<TKey, TElement> 是預先計算好的,因此可以多次查詢而不會重復執行分組操作。這對于需要頻繁訪問分組結果的應用場景非常有用。
3)使用場景
- 數據分類:當需要根據某個屬性或多個屬性對數據進行分類時。
- 頻繁查詢分組結果:當需要頻繁查詢分組結果且希望避免重復執行分組操作時。
- 不可變的分組結果:當需要一個不可變的分組結果時。
3. 使用示例
示例 1:基本分組
假設我們有一個包含若干 Person
對象的列表,每個對象都有 Name
和 Age
屬性。我們希望根據 Age
屬性對這些對象進行分組。
class Person
{public string Name { get; set; }public int Age { get; set; }public override string ToString(){return $"{Name} ({Age})";}
}class Program
{static void Main(){List<Person> people = new List<Person>{new Person { Name = "Alice", Age = 30 },new Person { Name = "Bob", Age = 25 },new Person { Name = "Charlie", Age = 30 },new Person { Name = "David", Age = 25 }};// 使用 ToLookup 根據 Age 屬性進行分組var lookupPeople = people.ToLookup(p => p.Age);foreach (var group in lookupPeople){Console.WriteLine($"Age: {group.Key}");foreach (var person in group){Console.WriteLine($" {person}");}}}
}
輸出結果:
Age: 30Alice (30)Charlie (30)
Age: 25Bob (25)David (25)
在這個例子中,我們使用 ToLookup
方法根據 Age
屬性對 people
列表進行了分組,并打印了每個組及其成員。
示例 2:選擇特定元素
有時我們只關心某些特定的屬性,而不是整個對象。在這種情況下,可以使用 elementSelector
參數來選擇要包含在組中的元素。
class Person
{public string Name { get; set; }public int Age { get; set; }public override string ToString(){return $"{Name} ({Age})";}
}class Program
{static void Main(){List<Person> people = new List<Person>{new Person { Name = "Alice", Age = 30 },new Person { Name = "Bob", Age = 25 },new Person { Name = "Charlie", Age = 30 },new Person { Name = "David", Age = 25 }};// 使用 ToLookup 并選擇特定元素(僅選擇 Name)var lookupNames = people.ToLookup(p => p.Age, p => p.Name);foreach (var group in lookupNames){Console.WriteLine($"Age: {group.Key}");foreach (var name in group){Console.WriteLine($" {name}");}}}
}
輸出結果:
Age: 30AliceCharlie
Age: 25BobDavid
在這個例子中,我們只選擇了 Name
屬性進行分組,并打印了每個組的名稱。
示例 3:自定義比較器
默認情況下,ToLookup
方法使用默認的相等比較器來比較鍵。如果需要自定義比較邏輯,可以傳遞一個 IEqualityComparer<TKey>
實現。
class Person
{public string Name { get; set; }public int Age { get; set; }public override string ToString(){return $"{Name} ({Age})";}
}class CustomComparer : IEqualityComparer<int>
{public bool Equals(int x, int y){// 自定義比較邏輯:年齡相差不超過1歲視為相同return Math.Abs(x - y) <= 1;}public int GetHashCode(int obj){return obj.GetHashCode();}
}class Program
{static void Main(){List<Person> people = new List<Person>{new Person { Name = "Alice", Age = 30 },new Person { Name = "Bob", Age = 25 },new Person { Name = "Charlie", Age = 30 },new Person { Name = "David", Age = 26 }};// 使用自定義比較器進行分組var customLookupPeople = people.ToLookup(p => p.Age, new CustomComparer());foreach (var group in customLookupPeople){Console.WriteLine($"Age: {group.Key}");foreach (var person in group){Console.WriteLine($" {person}");}}}
}
輸出結果:
Age: 30Alice (30)Charlie (30)
Age: 25Bob (25)
Age: 26David (26)
在這個例子中,我們使用了一個自定義的比較器來分組年齡相差不超過1歲的人員。實際上并沒有生效。
示例 4:多列分組
class Person
{public string Name { get; set; }public int Age { get; set; }public override string ToString(){return $"{Name} ({Age})";}
}class Program
{static void Main(){List<Person> people = new List<Person>{new Person { Name = "Alice", Age = 30 },new Person { Name = "Bob", Age = 25 },new Person { Name = "Charlie", Age = 30 },new Person { Name = "David", Age = 25 }};// 使用 ToLookup 進行多列分組(根據 Age 和 Name)var lookupByAgeAndName = people.ToLookup(p => new { p.Age, p.Name });foreach (var group in lookupByAgeAndName){Console.WriteLine($"Age: {group.Key.Age}, Name: {group.Key.Name}");foreach (var person in group){Console.WriteLine($" {person}");}}}
}
輸出結果:
Age: 30, Name: AliceAlice (30)
Age: 25, Name: BobBob (25)
Age: 30, Name: CharlieCharlie (30)
Age: 25, Name: DavidDavid (25)
在這個例子中,我們根據 Age
和 Name
屬性創建了一個復合鍵,并對 people
列表進行了分組。
示例 5:多次查詢
由于 ILookup<TKey, TElement> 是預先計算好的,因此可以多次查詢而不會重復執行分組操作。例如:
var lookupPeople = people.ToLookup(p => p.Age);// 第一次查詢
foreach (var group in lookupPeople)
{Console.WriteLine($"Age: {group.Key}");foreach (var person in group){Console.WriteLine($" {person}");}
}// 第二次查詢
if (lookupPeople.Contains(30))
{Console.WriteLine("Age 30 exists:");foreach (var person in lookupPeople[30]){Console.WriteLine($" {person}");}
}
在這個例子中,我們展示了如何多次查詢同一個 ILookup<TKey, TElement> 對象而不重復執行分組操作。
4. ILookup<TKey, TElement>
接口
ILookup<TKey, TElement>
接口提供了以下主要成員:
- Item[TKey]:通過鍵訪問對應的元素集合。
- Count:獲取組的數量。
- Contains(TKey):檢查是否存在具有指定鍵的組。
示例 1:使用 ILookup
的特性
class Person
{public string Name { get; set; }public int Age { get; set; }public override string ToString(){return $"{Name} ({Age})";}
}class Program
{static void Main(){List<Person> people = new List<Person>{new Person { Name = "Alice", Age = 30 },new Person { Name = "Bob", Age = 25 },new Person { Name = "Charlie", Age = 30 },new Person { Name = "David", Age = 25 }};// 使用 ToLookup 根據 Age 屬性進行分組var lookupPeople = people.ToLookup(p => p.Age);// 通過鍵訪問對應的元素集合if (lookupPeople.Contains(30)){Console.WriteLine("Age 30 exists:");foreach (var person in lookupPeople[30]){Console.WriteLine($" {person}");}}// 獲取組的數量Console.WriteLine($"Total groups: {lookupPeople.Count}");}
}
輸出結果:
Age 30 exists:Alice (30)Charlie (30)
Total groups: 2
在這個例子中,我們展示了如何使用 ILookup
的特性,如通過鍵訪問對應的元素集合、檢查是否存在具有指定鍵的組以及獲取組的數量。
4. 注意事項
- ToLookup 方法是一個立即執行的操作,這意味著它會立即對源集合進行分組操作,并將結果存儲在 Lookup 對象中。
- 分組鍵必須是可比較的,否則會引發異常。
- 如果源集合為空,ToLookup 方法將返回一個空的 Lookup 對象。
四、 ToLookup 和 GroupBy 的區別
Enumerable.ToLookup
是 LINQ(Language Integrated Query)中的一個方法,用于將數據源轉換為 ILookup<TKey, TElement>
類型的對象。與 GroupBy
方法類似,ToLookup
也用于對集合進行分組,但有一些關鍵的區別:
1. 概覽
1)Enumerable.ToLookup
- 即時求值:
ToLookup
方法會立即遍歷整個源集合并構建結果。 - 不可變性:返回的
ILookup<TKey, TElement>
對象是只讀的,一旦創建就不能修改。 - 多次查詢:由于
ILookup<TKey, TElement>
是預先計算好的,因此可以多次查詢而不會重復執行分組操作。 - 返回類型:返回一個
ILookup<TKey, TElement>
集合。
2)Enumerable.GroupBy
- 惰性求值:
GroupBy
方法采用惰性求值,只有在實際遍歷時才會執行分組操作。 - 可變性:返回的
IEnumerable<IGrouping<TKey, TElement>>
對象是可變的,可以根據需要動態添加或移除元素(盡管通常不建議這樣做)。 - 單次查詢:每次遍歷時都會重新執行分組操作,適合處理流式數據或無限序列。
- 返回類型:返回一個
IEnumerable<IGrouping<TKey, TElement>>
集合。
2. 主要區別
1. 求值方式
-
ToLookup:立即求值。調用
ToLookup
方法時,它會立即遍歷整個源集合并構建結果。這意味著所有分組操作在調用時完成,并且結果存儲在內存中。這可能會消耗更多的內存,特別是在處理大型數據集時。var lookup = source.ToLookup(x => x.Key); // 立即執行分組操作
-
GroupBy:惰性求值。調用
GroupBy
方法時,它并不會立即執行分組操作,而是等到實際遍歷時才進行計算。這使得GroupBy
可以處理無限序列或延遲執行復雜的查詢。這可以節省內存,特別是在處理大型數據集時。var groupBy = source.GroupBy(x => x.Key); // 分組操作直到實際遍歷時才會執行
2. 結果類型與特性
-
ToLookup:返回一個
ILookup<TKey, TElement>
對象,該對象是只讀的,并且支持通過鍵快速訪問對應的元素集合。var lookup = source.ToLookup(x => x.Key); foreach (var group in lookup) {Console.WriteLine($"Key: {group.Key}");foreach (var item in group){Console.WriteLine($" {item}");} }// 通過鍵訪問特定組 if (lookup.Contains(someKey)) {foreach (var item in lookup[someKey]){Console.WriteLine(item);} }
-
GroupBy:返回一個
IEnumerable<IGrouping<TKey, TElement>>
集合,每個IGrouping<TKey, TElement>
對象包含一個鍵和屬于該鍵的所有元素。由于是惰性求值,每次遍歷時都會重新執行分組操作。var groupBy = source.GroupBy(x => x.Key); foreach (var group in groupBy) {Console.WriteLine($"Key: {group.Key}");foreach (var item in group){Console.WriteLine($" {item}");} }
3. 多次查詢
-
ToLookup:由于
ILookup<TKey, TElement>
是預先計算好的,因此可以多次查詢而不會重復執行分組操作。這對于需要頻繁訪問分組結果的應用場景非常有用。var lookup = source.ToLookup(x => x.Key); // 第一次查詢 foreach (var group in lookup) { ... }// 第二次查詢 if (lookup.Contains(someKey)) { ... }
-
GroupBy:每次遍歷時都會重新執行分組操作。如果需要多次查詢同一個分組結果,可能會導致性能問題。
var groupBy = source.GroupBy(x => x.Key); // 每次遍歷時都會重新執行分組操作 foreach (var group in groupBy) { ... }
4. 自定義比較器
-
ToLookup:可以通過傳遞
IEqualityComparer<TKey>
實現來使用自定義比較器。var customLookup = source.ToLookup(x => x.Key, new CustomComparer());
-
GroupBy:也可以通過傳遞
IEqualityComparer<TKey>
實現來使用自定義比較器。var customGroupBy = source.GroupBy(x => x.Key, new CustomComparer());
5. 投影分組結果
-
ToLookup:可以使用
elementSelector
參數來自定義分組后的結果。var lookup = source.ToLookup(x => x.Key, x => x.Value);
-
GroupBy:同樣可以使用
elementSelector
/resultSelector
參數來自定義分組后的結果。var groupBy = source.GroupBy(x => x.Key, x => x.Value);
3. 適用場景
1. ToLookup
的適用場景
-
頻繁查詢:當你需要頻繁查詢分組結果,并希望避免重復執行分組操作時,
ToLookup
是更好的選擇。var lookup = people.ToLookup(p => p.Age); // 可以多次查詢不同的年齡組
-
固定數據集:當你的數據集是固定的,不需要動態添加或移除元素時,
ToLookup
更加合適。var lookup = fixedData.ToLookup(x => x.Key);
-
高性能需求:由于
ToLookup
是立即求值的,對于需要高性能的應用場景,它可以提供更快的查詢速度。
2. GroupBy
的適用場景
-
惰性求值:當你需要處理流式數據或無限序列時,
GroupBy
的惰性求值特性非常適合這種場景。var infiniteNumbers = Enumerable.Range(0, int.MaxValue).Select(i => i * 2); var groupedNumbers = infiniteNumbers.GroupBy(n => n % 3);
-
動態數據集:如果你的數據集是動態變化的,并且你可能需要根據新的數據動態調整分組結果,
GroupBy
更加靈活。var dynamicData = GetDataStream(); var groupBy = dynamicData.GroupBy(x => x.Key);
-
一次性查詢:如果你只需要對數據進行一次分組查詢,那么
GroupBy
可能更簡單且高效。
Enumerable.ToLookup
和 Grouping.GroupBy
都是 LINQ 中用于對集合進行分組的方法,但它們在返回類型和使用場景上有一些重要的區別。
結語
回到目錄頁:C#/.NET 知識匯總
希望以上內容可以幫助到大家,如文中有不對之處,還請批評指正。
參考資料:
微軟官方文檔 Enumerable