C# LINQ 基礎: 取得內容 大全(First, Last, Take, Skip, Single, Max, Min)


一開始在使用 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

留言