[食譜好菜] C# 兩個集合的 JOIN,一對一、一對多、單鍵值、多鍵值一次介紹。

不知道各位朋友在 C# 裡面,要將兩個集合 JOIN 起來使用時,是怎麼處理的? 假定我有一個 Employee 類別,有一個 Department 的屬性,Department 的內容需要透過另一個屬性 DepartmentId 到 Department 的集合當中去查找,如果各位朋友習慣上是使用類似下面寫法的話,可以嘗試改用另一種方法。

foreach (var employee in employees)
{
    employee.Department = departments.Single(dep => dep.Id == employee.DepartmentId);
}

Join()

Join() 方法從 .NET Framework 3.5 就一直存在至今,上面的寫法改用 Join() 方法就會變這樣:

var result = employees.Join(
        departments,
        emp => emp.DepartmentId,
        dep => dep.Id,
        (emp, dep) =>
            {
                emp.Department = dep;

                return emp;
            })
    .ToList();

那我們為什麼要用 Join() 方法?或許這時候會有一個聲音出現「面對 Lambda 語法的衝擊,我們這些守舊的老人家受不了啊!」,二話不多說,我們直接進入效能火拼環節,我用 BenchmarkDotNet 把這兩種寫法拿來做比較,Employee 集合及 Department 集合的個數,分別是 100 個及 10 個,不多吧,下面是跑出來的結果:

foreach 寫法的速度是 Join() 寫法的 3.33 倍,集合的個數愈多,差距愈大,那當然守舊的老人家可能會說「foreach 寫法我可以優化啊!」,對,你說得對!生命就該浪費在美好的事物上,這件拯救世界的任務就交給你了,我先下班了。

GroupJoin()

Join() 方法是處理一對一關係的兩個集合,如果是一對多關係的,要用 GroupJoin() 方法,我延伸我的範例,假定每位 Employee 需要負責保管公司內若干個 Equipment,因此 Employee 多了一個 Equipments 的屬性,所以 Employee 與 Equipment 就是一個一對多的關係,程式碼如下:

var result = employees.GroupJoin(
        equipments,
        emp => emp.Id,
        eqp => eqp.Custodian,
        (emp, eqps) =>
            {
                emp.Equipments = eqps.ToList();

                return emp;
            })
    .ToList();

我範例的設定是公司內有 1000 個 Equipments,每位 Employee 保管的數量不一定,效能上 GroupJoin() 方法依舊屌打 foreach 寫法。

這邊有一件事情要特別說明一下,一對多關係中的「多」代表 0 到多個(0 ~ n),所以 0 到 1 個(0 ~ 1)也是屬於一對多關係,應該用 GroupJoin() 而不是 Join()。

多鍵值

剛剛介紹的寫法是單鍵值的,現在來介紹多鍵值的處理方法,我繼續延伸我的範例,假定不同部門加上不同職級,薪水都不一樣,因此 Employee 就多了 RankSalary 屬性,Salary 的內容就利用 DepartmentId 及 Rank 當鍵值到 Salary 集合當中去查找,程式碼如下:

var result = employees.Join(
        salaries,
        emp => new { emp.DepartmentId, emp.Rank },
        slr => new { slr.DepartmentId, slr.Rank },
        (emp, slr) =>
            {
                emp.Salary = slr;

                return emp;
            })
    .ToList();

我們宣告相同結構的匿名型別來組合多鍵值,所以多鍵值的集合一樣可以 Join,以上就是 Join() 及 GroupJoin() 的使用方式分享給大家,底下有 Source Code 提供給大家參考。

參考資料

C# 指南ASP.NET 教學ASP.NET MVC 指引
Azure SQL Database 教學SQL Server 教學Xamarin.Forms 教學