在 C# 中,LINQ 是非常常使用到的,不過相關的介紹好像沒有像其他的那麼多,於是最近打算介紹多一點 LINQ 相關的內容。
在本文中會使用到兩個物件存放資料,物件格式如下:
建立測試資料:
可以看到我們有故意留下 004, 005 沒有成績,而成績清單中反向向排序,且有一個學號 100 號的 100 分,但是沒有被包含在學生清單中,方便我們觀察結果。
在下面的示範中會嘗試使用學號做對應,將學生姓名和成績輸出
Join 共有五個參數,只是因為是「擴充方法(Extension Methods)」,所以第一個參數會在 Join 關鍵字的左側。
參數:
上方的 new { student.Name, testScore.Score } 是匿名型別,不用事先明確定義類型,可以直接產生唯獨內容的物件,方便我們快速取得資料。
執行結果:
使用第一個清單順序,且只有兩者相符的內容才有被輸出。
執行結果:
依然使用第一個清單順序,且就算沒有被包含在清單二中的內容也會被輸出。
參考資料:
Microsoft.Learn - Extension Methods (C# Programming Guide)
Microsoft.Learn - Anonymous types
Microsoft.Learn - ?? and ??= operators (C# reference)
Microsoft.Learn - Enumerable.Join Method
Microsoft.Learn - Enumerable.GroupJoin Method
在本文中會使用到兩個物件存放資料,物件格式如下:
/// <summary>
/// 學生
/// </summary>
/// <param name="No">學號</param>
/// <param name="Name">姓名</param>
public record Student(string No, string Name);
/// <summary>
/// 測驗成績
/// </summary>
/// <param name="No">學號</param>
/// <param name="Score">成績</param>
public record TestScore(string No, int Score);
建立測試資料:
// 學生清單
Student[] students =
{
new Student("001", "小明"),
new Student("002", "大頭"),
new Student("003", "張三"),
new Student("004", "李四"),
new Student("005", "王五"),
};
// 測驗成績清單
TestScore[] testScores =
{
new TestScore("100", 100),
new TestScore("003", 90),
new TestScore("002", 80),
new TestScore("001", 70),
};
可以看到我們有故意留下 004, 005 沒有成績,而成績清單中反向向排序,且有一個學號 100 號的 100 分,但是沒有被包含在學生清單中,方便我們觀察結果。
在下面的示範中會嘗試使用學號做對應,將學生姓名和成績輸出
內部連接 - Inner Join
內部連接連接為兩邊都有資料時才會顯示,資料量是所有連接方式中最少的,使用 Join 關鍵字。Join 共有五個參數,只是因為是「擴充方法(Extension Methods)」,所以第一個參數會在 Join 關鍵字的左側。
參數:
- 第一個清單
- 第二個清單
- 第一個清單中用來和第二個清單中內容對應的成員
- 第二個清單中用來和第一個清單中內容對應的成員
- 回傳的結果(在兩個清單中都有的內容)
var list = students.Join(
testScores,
student => student.No,
testScore => testScore.No,
(student, testScore) => new { student.Name, testScore.Score }
).ToList();
上方的 new { student.Name, testScore.Score } 是匿名型別,不用事先明確定義類型,可以直接產生唯獨內容的物件,方便我們快速取得資料。
執行結果:
list.ForEach(item => Console.WriteLine($"姓名:{item.Name}, 成績:{item.Score}"));
/*
姓名:小明, 成績:70
姓名:大頭, 成績:80
姓名:張三, 成績:90
*/
使用第一個清單順序,且只有兩者相符的內容才有被輸出。
左外部連接 - Left Join
Left Join 是我們在資料庫中常用的方法,在 LINQ 中叫做 GroupJoin 。差別在於第一個清單中的內容就算不在第二個清單中也會被輸出,只是因為沒有在第二個清單中也會被輸出,所以第二個清單中的物件可能會是 NULL,在使用時可以利用 FirstOrDefault() 擴充方法來將找不到時的物件變為預設(NULL),再使用 ?? 運算子安全的將空物件內容賦值即可
var list = students.GroupJoin(
testScores,
student => student.No,
testScore => testScore.No,
(student, testScore) => new { student.Name, Score = testScore.FirstOrDefault()?.Score ?? 0 }
).ToList();
執行結果:
list.ForEach(item => Console.WriteLine($"姓名:{item.Name}, 成績:{item.Score}"));
/*
姓名:小明, 成績:70
姓名:大頭, 成績:80
姓名:張三, 成績:90
姓名:李四, 成績:0
姓名:王五, 成績:0
*/
依然使用第一個清單順序,且就算沒有被包含在清單二中的內容也會被輸出。
全部外部連接 - Full Join
FULL JOIN 一樣是在資料庫中常用的關鍵字,是指只要清單一或清單二有就輸出,不過很可惜的是在 C# 中並沒有像是 Full Join 的方法可以使用,如果需要的話可以參考 Stack Overflow 中的 LINQ - Full Outer Join參考資料:
Microsoft.Learn - Extension Methods (C# Programming Guide)
Microsoft.Learn - Anonymous types
Microsoft.Learn - ?? and ??= operators (C# reference)
Microsoft.Learn - Enumerable.Join Method
Microsoft.Learn - Enumerable.GroupJoin Method
留言
張貼留言
如果有任何問題、建議、想說的話或文章題目推薦,都歡迎留言或來信: a@ruyut.com