不知道各位朋友在 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 就多了 Rank
及 Salary
屬性,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 提供給大家參考。