繼上一篇講到透過 LINQ 的 from, where, select 和 orderby 後
這篇要講的是如何使用「groupby」將資料做群組分類
其中「groupby」分成「group」和「by」(擴充方法則使用「GroupBy」)
一樣使用上一篇的資料內容「students」
List<Student> students = new List<Student> { new Student { name = "Huadi", score = 90, id = "10001", phone = "0987654321", location = "A"}, new Student { name = "Jason", score = 80, id = "10002", phone = "0987654324", location = "B"}, new Student { name = "Tim", score = 85, id = "10003", phone = "0987654323", location = "D"}, new Student { name = "Vicky", score = 47, id = "10004", phone = "0987654326", location = "C"}, new Student { name = "Anny", score = 65, id = "10005", phone = "0987654322", location = "A"}, new Student { name = "Eric", score = 43, id = "10006", phone = "0987654325", location = "B"} };
從資料的內容來看,很容易的可以看出可以使用「location」來做分類是比較適合的
(上一篇的「location」是有加上數字,這裡我們暫時將數字拿掉,只剩下英文)
使用方法為:
group 資料 by 群組依據
// 使用 group by 依 location 將學生分組 var query = from stu in students group stu by stu.location; foreach (var q in query) { Console.WriteLine("Group - {0} :", q.Key); foreach (var item in q) { Console.WriteLine("Name = \"{0}\", Score = {1}", item.name, item.score); } }
在迴圈的部分
第一層迴圈會讀到的是有哪些群組,例如範例中是”A”, “B”, “C” 和 “D”
讀取則使用「key」來得到群組的值
而第二層迴圈則會讀到該群組的子資料
讀取的方法則和原來讀資料的方式一樣
(省略「select」,則預設會自動將資料的所有欄位讀進來)
輸出結果如下:
除了讓系統自行判斷內容分組外
我們也可以給定某個值,讓 LINQ 依照我們給的值去做群組的分類
例如:我們想把學生依照成績,分成及格的學生和不及格的學生
而一樣使用 group by 的方式,只是我們把判斷式寫上去
將程式碼修改如下:
// 使用 group by 依 score >= 60 將學生分組 var query = from stu in students group stu by stu.score >= 60;
此時,我們來看一下這個「key」的型別
它變成了「bool」型別了
你可以將程式碼改回原先的,依「location」來做分群組的程式碼
因為是透過「string」的比較,所以得出來的「key」,會是一個「string」的型別
但我們後來給的是一個判斷是,也就是說,群出分出來的結果,不是「True」就是「False」
所以型別當然就會是「bool」型別囉
我們輸出的結果就會變成這樣:
可以自行加入判斷,讓「key」是「True」的時候顯示「及格」,「False」時顯示「不及格」
// 使用 group by 依 score >= 60 將學生分組 var query = from stu in students group stu by stu.score >= 60; foreach (var q in query) { string display = q.Key ? "及格" : "不及格"; Console.WriteLine("Group - {0} :", display); foreach (var item in q) { Console.WriteLine("Name = \"{0}\", Score = {1}", item.name, item.score); } }
複合鍵群組
groupby 也可以讓分類的依據不只一個
如果今天想依「score」分類和「location」分類的話
可以使用「匿名型別」的方式,將分類的依據型成一個小群組
使用方法如下:
group 資料 by new { 分類一, 分類二}
因為這個例子的關係,我們特別加上一個屬性為「city」,代表每個人居住的城市
程式碼如下:
// 學生的名稱、成績、學號、電話和座位 List<Student> students = new List<Student> { new Student { name = "Huadi", score = 90, id = "10001", phone = "0987654321", location = "A", city = "Taipei"}, new Student { name = "Jason", score = 80, id = "10002", phone = "0987654324", location = "B", city = "Taichung"}, new Student { name = "Tim", score = 85, id = "10003", phone = "0987654323", location = "D", city = "Taipei"}, new Student { name = "Vicky", score = 47, id = "10004", phone = "0987654326", location = "C", city = "Taichung"}, new Student { name = "Anny", score = 65, id = "10005", phone = "0987654322", location = "A", city = "Taipei"}, new Student { name = "Eric", score = 43, id = "10006", phone = "0987654325", location = "B", city = "Taichung"} }; // 使用 group by 依 score >= 60 將學生分組 var query = from stu in students group stu by new { stu.location, stu.city }; foreach (var q in query) { Console.WriteLine("City - {0} , Location - {1}", q.Key.city, q.Key.location); foreach (var item in q) { Console.WriteLine("Name = \"{0}\", Score = {1}", item.name, item.score); } } Console.Read();
而原本的「key」變成一個為「Grouping」的匿名型別
在「key」中包含了「city」和「location」
在第一層可以得到群組的名稱
第二層就如同前面一樣,讀取每個群組中的資料
輸出結果如下:
可以看出,因為「Huadi」和「Anny」的「city」都是「Taipei」,且「location」都是「A」
因此被分類在同一個群組,其他的以此類推
在下一篇
將會講到如何使用 「Join」 實現多份資料表的交叉比對
在使用資料庫的資料表時非常容易使用到
也會順便接續前面兩篇
簡單的說明如何使用 LINQ 來讀取資料庫中的資料
如果想要自訂群組可以用類似
string[] StringSet={ 字串集合…… };
var query1=StringSet.GroupBy(s=>s,new StringComparer());
那如果不想用Lambda運算式 想要用 查詢運算式
var query2=from S in StringSet
group S by new StringComparer();
但這樣跑出的結果很奇怪 請問要如何修改?
LikeLike