[C#]LINQ–GroupBy 群組

繼上一篇講到透過 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」,則預設會自動將資料的所有欄位讀進來)

 

輸出結果如下:

 

image

 


除了讓系統自行判斷內容分組外

 

我們也可以給定某個值,讓 LINQ 依照我們給的值去做群組的分類

 

例如:我們想把學生依照成績,分成及格的學生和不及格的學生

 

而一樣使用 group by 的方式,只是我們把判斷式寫上去

 

將程式碼修改如下:

 

// 使用 group by 依 score >= 60 將學生分組
            var query = from stu in students
                        group stu by stu.score >= 60;

 

此時,我們來看一下這個「key」的型別

 

image

 

它變成了「bool」型別了

 

你可以將程式碼改回原先的,依「location」來做分群組的程式碼

 

因為是透過「string」的比較,所以得出來的「key」,會是一個「string」的型別

 

但我們後來給的是一個判斷是,也就是說,群出分出來的結果,不是「True」就是「False」

 

所以型別當然就會是「bool」型別囉

 

我們輸出的結果就會變成這樣:

 

image

 

可以自行加入判斷,讓「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」

 

在第一層可以得到群組的名稱

 

第二層就如同前面一樣,讀取每個群組中的資料

 

輸出結果如下:

 

image

 

可以看出,因為「Huadi」和「Anny」的「city」都是「Taipei」,且「location」都是「A」

 

因此被分類在同一個群組,其他的以此類推

 


在下一篇

 

將會講到如何使用 「Join」 實現多份資料表的交叉比對

 

在使用資料庫的資料表時非常容易使用到

 

也會順便接續前面兩篇

 

簡單的說明如何使用 LINQ 來讀取資料庫中的資料

One thought on “[C#]LINQ–GroupBy 群組

  1. 如果想要自訂群組可以用類似
    string[] StringSet={ 字串集合…… };
    var query1=StringSet.GroupBy(s=>s,new StringComparer());
    那如果不想用Lambda運算式 想要用 查詢運算式
    var query2=from S in StringSet
    group S by new StringComparer();
    但這樣跑出的結果很奇怪 請問要如何修改?

    Like

Leave a comment