一開始在使用 LINQ 時取回的結果通常都是集合,那該如何取得指定的內容呢?本篇整理了許多 LINQ 會使用到的取回特定項目的方式。
註: 本篇文章使用 .NET 6 (C# 10) 的語法做示範,舊版本的使用上可能會有些許差異。
取得第一個
List<int> list = new() { 1, 2, 3 };
var first = list.First();
Console.WriteLine($"First: {first}");
// First: 1
使用上面的方法可以將集合中的第一個內容取出,只是需要確保集合內有至少有一個內容,否則就會拋出例外:
List<int> list = new() { };
var first = list.First(); // 拋出例外
/*
Unhandled exception. System.InvalidOperationException: Sequence contains no elements
at System.Linq.ThrowHelper.ThrowNoElementsException()
at System.Linq.Enumerable.First[TSource](IEnumerable`1 source)
at Program.<Main>$(String[] args)
*/
不過還有另一種寫法: FirstOrDefault
如果找不到內容就回傳預設值:
List<int> list = new() { };
var first = list.FirstOrDefault();
Console.WriteLine($"First: {first}"); // First: 0
在 FirstOrDefault 也可以傳入參數,用於指定預設值:
List<int> list = new() { };
var first = list.FirstOrDefault(-1);
Console.WriteLine($"First: {first}"); // First: -1
取得最後一個
與 First 相對的也有 Last ,用來取得最後一個:
List<int> list = new() { 1, 2, 3 };
var last = list.Last();
Console.WriteLine($"Last: {last}"); // Last: 3
也有 LastOrDefault 用來在沒有內容時回傳預設值:
List<int> list = new() { };
var last = list.LastOrDefault();
Console.WriteLine($"Last: {last}"); // Last: 0
取得前幾筆
如果要取得不只一個呢?使用 Take:
List<int> list = new() { 1, 2, 3 };
var ints = list.Take(5);
Console.WriteLine($"Count: {ints.Count()}"); // Count: 3
Console.WriteLine($"ints: {string.Join(", ", ints)}"); // ints: 1, 2, 3
內容不足並不會拋出例外,而是只回傳可以取得到的最多的內容
取得後幾筆
使用 TakeLast 可以取得最後的幾筆,不過順序並不會反過來,結果會和使用 Take 時一樣的順序
List<int> list = new() { 1, 2, 3 };
var ints = list.TakeLast(5);
Console.WriteLine($"Count: {ints.Count()}"); // Count: 3
Console.WriteLine($"ints: {string.Join(", ", ints)}"); // ints: 1, 2, 3
跳過前幾筆
List<int> list = new() { 1, 2, 3, 4, 5 };
var ints = list.Skip(2);
Console.WriteLine($"Count: {ints.Count()}"); // Count: 3
Console.WriteLine($"ints: {string.Join(", ", ints)}"); // ints: 3, 4, 5
跳過後幾筆
List<int> list = new() { 1, 2, 3, 4, 5 };
var ints = list.Skip(2);
Console.WriteLine($"Count: {ints.SkipLast()}"); // Count: 3
Console.WriteLine($"ints: {string.Join(", ", ints)}"); // ints: 1, 2, 3
取得符合條件的單一元素
List<string> list = new() { "apple", "banana", "orange" };
var single = list.Single(x => x.Length == 5);
Console.WriteLine($"Single: {single}"); // Single: apple
如果可以取得的找不到或是不只一個就會拋出例外:
List<string> list = new() { "apple", "banana", "orange" };
var single = list.Single(x => x.Length == 6); // 拋出例外
/*
Unhandled exception. System.InvalidOperationException: Sequence contains more than one matching element
at System.Linq.ThrowHelper.ThrowMoreThanOneMatchException()
at System.Linq.Enumerable.TryGetSingle[TSource](IEnumerable`1 source, Func`2 predicate, Boolean& found)
at System.Linq.Enumerable.Single[TSource](IEnumerable`1 source, Func`2 predicate)
at Program.<Main>$(String[] args)
*/
在找不到的情況下可以使用 SingleOrDefault 來避免拋出例外,不過如果有多筆符合還是會拋出例外:
List<string> list = new() { "apple", "banana", "orange" };
var single = list.SingleOrDefault(x => x.Length == 7); // null
取得最大
使用 Max 可以取得最大值:
List<int> list = new() { 1, 2, 3, 2, 1 };
int result = list.Max();
Console.WriteLine($"Max: {result}"); // Max: 3
如果集合為空時也會拋出例外: System.InvalidOperationException: Sequence contains no elements
對於自訂類別也可以使用 MaxBy 來自訂排序,取得最大的內容:
自訂類別:
List<Student> students = new()
{
new Student { Id = 1, Name = "小明" },
new Student { Id = 2, Name = "大頭" },
new Student { Id = 3, Name = "小美" },
new Student { Id = 4, Name = "大熊" }
};
使用 MaxBy 依照 Id 找出最大的 Student
Student student = students.MaxBy(x => x.Id);
Console.WriteLine($"Max: {student.Id}, {student.Name}");
// Max: 4, 大熊
取得最小
取得最小使用 Min 和 MinBy ,使用方式和 Max 與 MaxBy 一樣,只是內容剛好相反:使用 Min 可以取得最小值:
List<int> list = new() { 1, 2, 3, 2, 1 };
int result = list.Min();
Console.WriteLine($"Min: {result}"); // Max: 1
使用 MinBy 依照 Id 找出最小的 Student
Student student = students.MinBy(x => x.Id);
Console.WriteLine($"MinBy: {student.Id}, {student.Name}");
// Max: 1, 小明
延伸閱讀: C# LINQ 從 0 到 1 基礎教學
參考資料:
Microsoft.Learn - Enumerable.First Method
Microsoft.Learn - Enumerable.FirstOrDefault Method
Microsoft.Learn - Enumerable.Last Method
Microsoft.Learn - Enumerable.LastOrDefault Method
Microsoft.Learn - Enumerable.Take Method
Microsoft.Learn - Enumerable.Skip<TSource>(IEnumerable<TSource>, Int32) Method
Microsoft.Learn - Enumerable.SkipLast<TSource>(IEnumerable<TSource>, Int32) Method
Microsoft.Learn - Enumerable.Single Method
Microsoft.Learn - Enumerable.SingleOrDefault Method
Microsoft.Learn - Enumerable.Max Method
Microsoft.Learn - Enumerable.MaxBy Method
Microsoft.Learn - Enumerable.Min Method
Microsoft.Learn - Enumerable.MinBy Method
留言
張貼留言
如果有任何問題、建議、想說的話或文章題目推薦,都歡迎留言或來信: a@ruyut.com