[C#] ToLookup, GroupBy, ToDictionary簡單介紹
前言
在我們將資料進行分組,
或是做一些Key => Value Mapping的動作時,
我們會經常使用到LINQ這三個方法,
而在ToLookup, GroupBy, ToDictionary這三個方法中,
ToLookup和GroupBy是比較接近的,
兩者都是將資料分組的動作,
而ToDictionary則是可以方便我們將資料的某個欄位抽取出來當作Key值。
實際演練
而既然ToLookup和GroupBy兩者都是將資料做分組,
那它們的本質上有什麼不同呢?
答案是GroupBy會 延遲執行 (Deffered Execution),
讓我們來看看範例說明。
我們先建立一個假資料的來源,模擬讀取資料庫。
public static List<Person> GetPersonList()
{
return new List<Person>()
{
new Person(){ID=1,Name="Kirk", Address="aaaa", Birthday=new DateTime(1985,6,8), Introduction="aaaa", Phone="0927896456",Group="A"},
new Person(){ID=2,Name="John", Address="bbbb", Birthday=new DateTime(1972,1,3), Introduction="aaaa", Phone="0927111111",Group="A"},
new Person(){ID=3,Name="David", Address="cccc", Birthday=new DateTime(1964,7,13), Introduction="aaaa", Phone="0927222222",Group="B"},
new Person(){ID=4,Name="Steven", Address="dddd", Birthday=new DateTime(1982,6,1), Introduction="aaaa", Phone="0927333333",Group="B"},
new Person(){ID=5,Name="Jason", Address="eeee", Birthday=new DateTime(1983,10,3), Introduction="aaaa", Phone="0927444444",Group="A"},
new Person(){ID=6,Name="Titan", Address="ffff", Birthday=new DateTime(1987,7,2), Introduction="aaaa", Phone="0927555555",Group="C"},
new Person(){ID=7,Name="Sophia", Address="gggg", Birthday=new DateTime(1981,3,27), Introduction="aaaa", Phone="0927666666",Group="A"},
new Person(){ID=8,Name="Mary", Address="hhhh", Birthday=new DateTime(1982,12,18), Introduction="aaaa", Phone="0927777777",Group="D"},
new Person(){ID=9,Name="Tom", Address="iiii", Birthday=new DateTime(1983,9,23), Introduction="aaaa", Phone="0927888888",Group="B"},
new Person(){ID=10,Name="Julia", Address="jjjj", Birthday=new DateTime(1975,3,18), Introduction="aaaa", Phone="0927999999",Group="A"},
};
}
首先我們來看看ToLookup的範例
var personList = GetPersonList();
var personListLookUp = personList.ToLookup(i => i.Group); // Execute query immediately
personList.RemoveAll(i => true);
foreach (var personGroup in personListLookUp)
{
Console.WriteLine("Group: {0}", personGroup.Key);
foreach (var person in personGroup)
{
Console.WriteLine("ID: {0}, Name: {1}", person.ID, person.Name);
}
}
執行結果:
Group: A
ID: 1, Name: Kirk
ID: 2, Name: John
ID: 5, Name: Jason
ID: 7, Name: Sophia
ID: 10, Name: Julia
Group: B
ID: 3, Name: David
ID: 4, Name: Steven
ID: 9, Name: Tom
Group: C
ID: 6, Name: Titan
Group: D
ID: 8, Name: Mary
我們可以發現,就算我們將personList中的資料都移除了,
也不會影響ToLookup所取得的資料,因為所有的資料都在ToLookup時就已經讀取完畢,
並回傳儲存至personListLookUp中了。
再來我們看看GroupBy的範例
var personList = GetPersonList();
var personListGroupBy = personList.GroupBy(i => i.Group); // Do not execute query
personList.RemoveAll(i => true);
foreach (var personGroup in personListGroupBy) // Do query now
{
Console.WriteLine("Group: {0}", personGroup.Key);
foreach (var person in personGroup)
{
Console.WriteLine("ID: {0}, Name: {1}", person.ID, person.Name);
}
}
會發現執行結果唯一空集合,
這是因為GroupBy會一直等到第一次去讀取資料內容時才執行Query,
而在那之前,原始資料已被清空了,自然就不會有任何結果,
這也是LINQ的一個叫做延遲執行的特性所造成的,
它可以方便我們在確認組完所有的Condition之後,再執行Query,以增進效能,
而在實際上使用時,我們也可根據使用情境的不同,來選擇要使用ToLookup或GroupBy
但在使用時就必須要瞭解它,來避免執行結果不是預期中的囉!
最後在附上一個ToDictionary的範例,
var personList = GetPersonList();
var personListDictionary = personList.ToDictionary(i => i.ID);
personList.RemoveAll(i => true);
foreach (var person in personListDictionary)
{
Console.WriteLine("ID: {0}, Name: {1}", person.Key, person.Value.Name);
}
執行結果:
ID: 1, Name: Kirk
ID: 2, Name: John
ID: 3, Name: David
ID: 4, Name: Steven
ID: 5, Name: Jason
ID: 6, Name: Titan
ID: 7, Name: Sophia
ID: 8, Name: Mary
ID: 9, Name: Tom
ID: 10, Name: Julia
結語
LINQ 是.Net Framework 3.5所增加的一個十分強大的新功能,
在熟悉了它之後幾乎無法忘掉它所帶來的種種好處,
但在享受它好處的同時,也不要忘記去理解它的一些原理,
以避免不小心掉入某些陷阱而不自知囉!
若以上說明有任何的問題或指教,還請大家多多包涵提出討論 ^^
參考連結: