Quantcast
Channel: 黑暗執行緒
Viewing all articles
Browse latest Browse all 2311

利用LINQ GroupBy快速分組歸類

$
0
0

分享最近學到的LINQ小技巧一則。有時我們會需求將資料物件分組擺放,方便後續查詢處理,例如:將散亂的銷售資料依客戶分群,同一客戶的所有資料變成一個List<T>。

過去面對這種問題,我慣用的做法先定義一個Dictionary<string, List<T>>,使用 foreach 逐筆抓取來源資料,從中取出鍵值(例如:客戶編號),先檢查鍵值是否已存在於Dictionary,若無則新増一筆並建立空的List<T>,確保Dictionary有該鍵值專屬List<T>,將資料放入List<T>。執行完畢得到以鍵值分類的List<T>,再進行後續處理。

foreach + Dictionary寫法用了好幾年,前幾天才忽然想到,這不就是SQL語法中的GROUP BY嗎?加上LINQ有ToDictionary, GroupBy(o => o.客戶編號).ToDictionary(o => o.Key, o => o.ToList()) 一行就搞定了呀!阿呆。

來個應景的程式範例吧!

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace LinqTip
{
class Program
    {
publicenum Teams
        {
            Valor, Mystic, Instinct, Dark
        }
 
publicclass Trainer
        {
public Teams Team;
publicstring Name;
public Trainer(Teams team, string name)
            {
                Team = team; Name = name;
            }
        }
 
staticvoid Main(string[] args)
        {
//來源資料如下
            List<Trainer> trainers = new List<Trainer>()
            {
new Trainer(Teams.Valor, "Candela"),
new Trainer(Teams.Valor, "Bob"),
new Trainer(Teams.Mystic, "Blanche"),
new Trainer(Teams.Valor, "Alice"),
new Trainer(Teams.Instinct, "Spark"),
new Trainer(Teams.Mystic, "Tom"),
new Trainer(Teams.Dark, "Jeffrey")
            };
//目標:以Team分類,將同隊的訓練師集合成List<Trainer>,
//最終產出Dictionary<Teams, List<Trainer>>
 
//以前的寫法,跑迴圈加邏輯比對
            var res1 = new Dictionary<Teams, List<Trainer>>();
foreach (var t in trainers)
            {
if (!res1.ContainsKey(t.Team))
                    res1.Add(t.Team, new List<Trainer>());
                res1[t.Team].Add(t);
            }
 
//新寫法,使用LINQ GroupBy
            var res2 =
                trainers.GroupBy(o => o.Team)
                .ToDictionary(o => o.Key, o => o.ToList());
        }
    }
}

就醬,又學會一招~

不過,GroupBy().ToDictionary() 做法適用分類現有資料,若之後要陸續接收新增資料,仍可回歸 foreach + Dictionary<string, List<T>> 寫法。

[2016-08-24補充] 感謝Phoenix補充,LINQ還有更簡潔的做法:ToLookup(o > o.Teams, o => o),其產出的型別為ILookup,以Key分組的Value集合,與Dictionary最大的差異是ILookup屬唯讀性質,事後不能變更或修改集合項目。


Viewing all articles
Browse latest Browse all 2311

Trending Articles