Toán tử phần tử trong LINQ

Toán tử phần tử (element operators) trả về một phần tử cụ thể từ một danh sách.

Bảng sau liệt kê tất cả các toán tử phần tử trong LINQ.

Toán tử Mô tả
ElementAt Trả về phần tử tại một chỉ mục được chỉ định trong danh sách. Nếu chỉ mục nằm ngoài phạm vi danh sách sẽ ném ra ngoại lệ.
ElementAtOrDefault Trả về phần tử tại một chỉ mục được chỉ định trong danh sách hoặc giá trị mặc định nếu chỉ mục nằm ngoài phạm vi.
First Trả về phần tử đầu tiên của danh sách hoặc phần tử đầu tiên thỏa mãn điều kiện. Nếu không có phần tử như vậy tồn tại sẽ ném ra ngoại lệ.
FirstOrDefault Trả về phần tử đầu tiên của danh sách hoặc phần tử đầu tiên thỏa mãn điều kiện. Trả về giá trị mặc định nếu không có phần tử như vậy tồn tại.
Last Trả về phần tử cuối cùng của danh sách hoặc phần tử cuối thỏa mãn điều kiện. Nếu không có phần tử như vậy tồn tại sẽ ném ra ngoại lệ.
LastOrDefault Trả về phần tử cuối cùng của danh sách hoặc phần tử cuối thỏa mãn điều kiện. Trả về một giá trị mặc định nếu không có phần tử như vậy tồn tại.
Single Trả về phần tử duy nhất của danh sách hoặc phần tử duy nhất thỏa mãn điều kiện. Nếu không có phần tử như vậy tồn tại sẽ ném ra ngoại lệ.
SingleOrDefault Trả về phần tử duy nhất của danh sách hoặc phần tử duy nhất thỏa mãn điều kiện. Trả về giá trị mặc định nếu không có phần tử nào như vậy tồn tại.

Toán tử tập hợp là một trong những toán tử truy vấn chuẩn của LINQ.

Toán tử truy vấn chuẩn của LINQ | Comdy
Các toán tử truy vấn chuẩn trong LINQ là các phương thức mở rộng cho các kiểu IEnumerable<T> và IQueryable<T>.

Phương thức ElementAt trong LINQ

Phương thức ElementAt trả về một phần tử theo chỉ mục đã chỉ định trong danh sách.

Nếu chỉ mục được chỉ định nằm ngoài phạm vi của danh sách thì nó sẽ ném ra ngoại lệ "Index out of range". Xin lưu ý rằng chỉ mục là một chỉ số bắt đầu từ 0.

Ví dụ sau đây minh họa phương thức ElementAt trên danh sách kiểu nguyên thủy.

IList<int> intList = new List<int>() { 10, 21, 30, 45, 50, 87 };
IList<string> strList = new List<string>() { "One", "Two", null, "Four", "Five" };

Console.WriteLine("1st Element in intList: {0}", intList.ElementAt(0));
Console.WriteLine("1st Element in strList: {0}", strList.ElementAt(0));
		
Console.WriteLine("2nd Element in intList: {0}", intList.ElementAt(1));
Console.WriteLine("2nd Element in strList: {0}", strList.ElementAt(1));		
		
Console.WriteLine("intList.ElementAt(9) throws an exception: Index out of range");
Console.WriteLine("---------------------------------------------------");
Console.WriteLine(intList.ElementAt(9));

Đây là kết quả khi biên dịch và thực thi chương trình:

1st Element in intList: 10
1st Element in strList: One
2nd Element in intList: 21
2nd Element in strList: Two
intList.ElementAt(9) throws an exception: Index out of range
-------------------------------------------------------------
Run-time exception: Index was out of range....

Như bạn có thể thấy trong ví dụ trên,intList.ElementAt(9) ném ra ngoại lệ "Index out of range". Do đó bạn cần phải kiểm tra chỉ mục cẩn thận để tránh xảy ra ngoại lệ khi sử dụng phương thức này.

Bạn có thể sử dụng phương thức ElementAtOrDefault sẽ được trình bày ngay bên dưới để tránh xảy ra ngoại lệ như phương thức ElementAt.

Phương thức ElementAtOrDefault trong LINQ

Giống như phương thức ElementAt, phương thức ElementAtOrDefault cũng trả về một phần tử theo chỉ mục đã chỉ định trong danh sách.

Tuy nhiên nếu chỉ mục được chỉ định nằm ngoài phạm vi của danh sách thì nó sẽ trả về giá trị mặc định thay vì ném ra ngoại lệ "Index out of range" như phương thức ElementAt.

Ví dụ sau đây minh họa phương thức ElementAtOrDefault trên danh sách kiểu nguyên thủy.

IList<int> intList = new List<int>() { 10, 21, 30, 45, 50, 87 };
IList<string> strList = new List<string>() { "One", "Two", null, "Four", "Five" };

Console.WriteLine("3rd Element in intList: {0}", intList.ElementAtOrDefault(2));
Console.WriteLine("3rd Element in strList: {0}", strList.ElementAtOrDefault(2));

Console.WriteLine("10th Element in intList: {0} - default int value", 
                intList.ElementAtOrDefault(9));		
Console.WriteLine("10th Element in strList: {0} - default string value",
                 strList.ElementAtOrDefault(9));

Đây là kết quả khi biên dịch và thực thi chương trình:

3rd Element in intList: 30
3rd Element in strList: Three
10th Element in intList: 0 - default int value
10th Element in strList: - default string value (null)

Như bạn thấy ở ví dụ trên, phương thức ElementAtOrDefault trả về giá trị mặc định khi chỉ mục nằm ngoại phạm vi của danh sách và không ném ra ngoại lệ như phương thức ElementAt.

Tip: nên sử dụng phương thức mở rộng ElementAtOrDefault thay thế cho phương thức ElementAt để loại trừ khả năng xảy ra ngoại lệ thời gian chạy.

Phương thức First trong LINQ

Phương thức First trả về phần tử đầu tiên của danh sách hoặc phần tử đầu tiên thỏa mãn điều kiện. Nếu không có phần tử như vậy tồn tại sẽ ném ra ngoại lệ.

Phương thức First có hai phương thức quá tải. Phương thức quá tải đầu tiên không lấy bất kỳ tham số đầu vào nào và trả về phần tử đầu tiên trong danh sách.

Phương thức quá tải thứ hai lấy biểu thức lambda làm predicate delegate để chỉ định một điều kiện và trả về phần tử đầu tiên thỏa mãn điều kiện đã chỉ định.


public static TSource First<TSource>(this IEnumerable<TSource> source);

public static TSource First<TSource>(this IEnumerable<TSource> source,
    Func<TSource, bool> predicate);

Phương thức First trả về phần tử đầu tiên của danh sách hoặc phần tử đầu tiên thỏa mãn điều kiện đã chỉ định bằng biểu thức lambda hoặc delegate Func.

Nếu một danh sách rỗng hoặc không có bất kỳ phần tử nào thỏa mãn điều kiện thì nó sẽ ném ra ngoại lệ InvalidOperation.

Ví dụ sau đây minh họa phương thức First:

IList<int> intList = new List<int>() { 7, 10, 21, 30, 45, 50, 87 };
IList<string> strList = new List<string>() { "One", "Two", "Three", "Four", "Five" };
IList<string> emptyList = new List<string>();
		
Console.WriteLine("1st Element in intList: {0}", intList.First());
Console.WriteLine("1st Even Element in intList: {0}", intList.First(i => i % 2 == 0));

Console.WriteLine("1st Element in strList: {0}", strList.First());

Console.WriteLine("emptyList.First() throws an InvalidOperationException");
Console.WriteLine("-----------------------------------------------------");
Console.WriteLine(emptyList.First());

Đây là kết quả khi biên dịch và thực thi chương trình:

1st Element in intList: 7
1st Even Element in intList: 10
1st Element in strList: One
emptyList.First() throws an InvalidOperationException
-----------------------------------------------------
Run-time exception: Sequence contains no elements...

Hãy cẩn thận trong khi chỉ định điều kiện trong phương thức First. Nó sẽ đưa ra một ngoại lệ nếu danh sách không có bất kỳ phần tử nào thỏa mãn điều kiện đã chỉ định.

Phương thức FirstOrDefault trong LINQ

Tương tự như phương thức First, phương thức FirstOrDefault cũng trả về phần tử đầu tiên của danh sách hoặc phần tử đầu tiên thỏa mãn điều kiện. Trả về giá trị mặc định nếu không có phần tử như vậy.

Phương thức FirstOrDefault cũng có hai phương thức quá tải. Phương thức quá tải đầu tiên không lấy bất kỳ tham số đầu vào nào và trả về phần tử đầu tiên trong danh sách.

Phương thức quá tải thứ hai lấy biểu thức lambda làm predicate delegate để chỉ định một điều kiện và trả về phần tử đầu tiên thỏa mãn điều kiện đã chỉ định.


public static TSource FirstOrDefault<TSource>(this IEnumerable<TSource> source);

public static TSource FirstOrDefault<TSource>(this IEnumerable<TSource> source,
    Func<TSource, bool> predicate);
    

Phương thức FirstOrDefault thực hiện tương tự như phương thức First. Sự khác biệt duy nhất là nó trả về giá trị mặc định của kiểu dữ liệu của danh sách nếu danh sách trống hoặc không tìm thấy bất kỳ phần tử nào thỏa mãn điều kiện.

Ví dụ sau đây minh họa phương thức FirstOrDefault:

IList<int> intList = new List<int>() { 7, 10, 21, 30, 45, 50, 87 };
IList<string> strList = new List<string>() { "One", "Two", "Three", "Four", "Five" };
IList<string> emptyList = new List<string>();
		
Console.WriteLine("1st Element in intList: {0}", intList.FirstOrDefault());
Console.WriteLine("1st Even Element in intList: {0}", intList.FirstOrDefault(i => i % 2 == 0));

Console.WriteLine("1st Element in strList: {0}", strList.FirstOrDefault());

Console.WriteLine("1st Element in emptyList: {0}", emptyList.FirstOrDefault());

Đây là kết quả khi biên dịch và thực thi chương trình:

1st Element in intList: 7
1st Even Element in intList: 10
1st Element in strList: One
1st Element in emptyList:
Tip: nên sử dụng phương thức mở rộng FirstOrDefault thay thế cho phương thức First để loại trừ khả năng xảy ra ngoại lệ thời gian chạy.

Phương thức Last trong LINQ

Trái ngược với phương thức First, Phương thức Last trả về phần tử cuối cùng của danh sách hoặc phần tử cuối cùng thỏa mãn điều kiện. Nếu không có phần tử như vậy tồn tại sẽ ném ra ngoại lệ.

Phương thức Last có hai phương thức quá tải. Phương thức quá tải đầu tiên không lấy bất kỳ tham số đầu vào nào và trả về phần tử cuối cùng trong danh sách.

Phương thức quá tải thứ hai lấy biểu thức lambda làm predicate delegate để chỉ định một điều kiện và trả về phần tử cuối cùng thỏa mãn điều kiện đã chỉ định.


public static TSource Last<TSource>(this IEnumerable<TSource> source);

public static TSource Last<TSource>(this IEnumerable<TSource> source,
    Func<TSource, bool> predicate);

Phương thức Last trả về phần tử cuối cùng của danh sách hoặc phần tử cuối cùng thỏa mãn điều kiện đã chỉ định bằng biểu thức lambda hoặc delegate Func.

Nếu một danh sách rỗng hoặc không có bất kỳ phần tử nào thỏa mãn điều kiện thì nó sẽ ném ra ngoại lệ InvalidOperation.

Ví dụ sau đây minh họa phương thức Last:

IList<int> intList = new List<int>() { 7, 10, 21, 30, 45, 50, 87 };
IList<string> strList = new List<string>() { "One", "Two", "Three", "Four", "Five" };
IList<string> emptyList = new List<string>();
		
Console.WriteLine("Last Element in intList: {0}", intList.Last());
Console.WriteLine("Last Even Element in intList: {0}", intList.Last(i => i % 2 == 0));

Console.WriteLine("Last Element in strList: {0}", strList.Last());

Console.WriteLine("emptyList.Last() throws an InvalidOperationException");
Console.WriteLine("-----------------------------------------------------");
Console.WriteLine(emptyList.Last());

Đây là kết quả khi biên dịch và thực thi chương trình:

Last Element in intList: 87
Last Even Element in intList: 50
Last Element in strList: Five
emptyList.Last() throws an InvalidOperationException
-----------------------------------------------------
Run-time exception: Sequence contains no elements...

Hãy cẩn thận trong khi chỉ định điều kiện trong phương thức Last. Nó sẽ đưa ra một ngoại lệ nếu danh sách không có bất kỳ phần tử nào thỏa mãn điều kiện đã chỉ định.

Phương thức LastOrDefault trong LINQ

Tương tự như phương thức Last, phương thức LastOrDefault cũng trả về phần tử cuối cùng của danh sách hoặc phần tử cuối cùng thỏa mãn điều kiện. Trả về giá trị mặc định nếu không có phần tử như vậy.

Phương thức LastOrDefault cũng có hai phương thức quá tải. Phương thức quá tải đầu tiên không lấy bất kỳ tham số đầu vào nào và trả về phần tử cuối cùng trong danh sách.

Phương thức quá tải thứ hai lấy biểu thức lambda làm predicate delegate để chỉ định một điều kiện và trả về phần tử cuối cùng thỏa mãn điều kiện đã chỉ định.


public static TSource LastOrDefault<TSource>(this IEnumerable<TSource> source);

public static TSource LastOrDefault<TSource>(this IEnumerable<TSource> source,
    Func<TSource, bool> predicate);
    

Phương thức LastOrDefault thực hiện tương tự như phương thức Last. Sự khác biệt duy nhất là nó trả về giá trị mặc định của kiểu dữ liệu của danh sách nếu danh sách trống hoặc không tìm thấy bất kỳ phần tử nào thỏa mãn điều kiện.

Ví dụ sau đây minh họa phương thức LastOrDefault:

IList<int> intList = new List<int>() { 7, 10, 21, 30, 45, 50, 87 };
IList<string> strList = new List<string>() { "One", "Two", "Three", "Four", "Five" };
IList<string> emptyList = new List<string>();
		
Console.WriteLine("Last Element in intList: {0}", intList.LastOrDefault());
Console.WriteLine("Last Even Element in intList: {0}", intList.LastOrDefault(i => i % 2 == 0));

Console.WriteLine("Last Element in strList: {0}", strList.LastOrDefault());

Console.WriteLine("Last Element in emptyList: {0}", emptyList.LastOrDefault());

Đây là kết quả khi biên dịch và thực thi chương trình:

Last Element in intList: 87
Last Even Element in intList: 50
Last Element in strList: Five
Last Element in emptyList:
Tip: nên sử dụng phương thức mở rộng LastOrDefault thay thế cho phương thức Last để loại trừ khả năng xảy ra ngoại lệ thời gian chạy.

Phương thức Single trong LINQ

Phương thức Single trả về phần tử duy nhất của danh sách hoặc phần tử duy nhất thỏa mãn điều kiện. Nếu không có phần tử như vậy tồn tại sẽ ném ra ngoại lệ.

Phương thức Single có hai phương thức quá tải. Phương thức quá tải đầu tiên không lấy bất kỳ tham số đầu vào nào và trả về phần tử duy nhất trong danh sách.

Phương thức quá tải thứ hai lấy biểu thức lambda làm predicate delegate để chỉ định một điều kiện và trả về phần tử duy nhất thỏa mãn điều kiện đã chỉ định.


public static TSource Single<TSource>(this IEnumerable<TSource> source);

public static TSource Single<TSource>(this IEnumerable<TSource> source,
    Func<TSource, bool> predicate);
    

Phương thức Single trả về phần tử duy nhất của danh sách hoặc phần tử duy nhất thỏa mãn điều kiện đã chỉ định bằng biểu thức lambda hoặc delegate Func.

Nếu một danh sách rỗng hoặc không có bất kỳ phần tử nào thỏa mãn điều kiện hoặc có nhiều hơn một phần tử thỏa mãn điều kiện thì nó sẽ ném ra ngoại lệ InvalidOperation.

Ví dụ sau đây minh họa phương thức Single:

IList<int> oneElementList = new List<int>() { 7 };
IList<int> intList = new List<int>() { 7, 10, 21, 30, 45, 50, 87 };
IList<string> strList = new List<string>() { null, "Two", "Three", "Four", "Five" };
IList<string> emptyList = new List<string>();

Console.WriteLine("The only element in oneElementList: {0}", oneElementList.Single());
Console.WriteLine("The only element which is less than 10 in intList: {0}",
             intList.Single(i => i < 10));

Console.WriteLine("emptyList.Single() throws an InvalidOperationException");
Console.WriteLine("-----------------------------------------------------");
Console.WriteLine(emptyList.Single());

Đây là kết quả khi biên dịch và thực thi chương trình:

The only element in oneElementList: 7
The only element which is less than 10 in intList: 7
emptyList.Single() throws an InvalidOperationException
-----------------------------------------------------
Run-time exception: Sequence contains no elements...

Hãy cẩn thận trong khi chỉ định điều kiện trong phương thức Single. Nó sẽ đưa ra một ngoại lệ nếu danh sách không có bất kỳ phần tử nào hoặc có nhiều hơn một phần tử thỏa mãn điều kiện đã chỉ định.

Phương thức SingleOrDefault trong LINQ

Tương tự như phương thức Single, phương thức SingleOrDefault cũng trả về phần tử duy nhất của danh sách hoặc phần tử duy nhất thỏa mãn điều kiện. Trả về giá trị mặc định nếu không có phần tử như vậy.

Phương thức SingleOrDefault cũng có hai phương thức quá tải. Phương thức quá tải đầu tiên không lấy bất kỳ tham số đầu vào nào và trả về phần tử duy nhất trong danh sách.

Phương thức quá tải thứ hai lấy biểu thức lambda làm predicate delegate để chỉ định một điều kiện và trả về phần tử duy nhất thỏa mãn điều kiện đã chỉ định.


public static TSource SingleOrDefault<TSource>(this IEnumerable<TSource> source);

public static TSource SingleOrDefault<TSource>(this IEnumerable<TSource> source,
    Func<TSource, bool> predicate);
    

Phương thức SingleOrDefault thực hiện tương tự như phương thức Single. Sự khác biệt duy nhất là nó trả về giá trị mặc định của kiểu dữ liệu của danh sách nếu danh sách trống hoặc không tìm thấy bất kỳ phần tử nào thỏa mãn điều kiện hoặc có nhiều hơn một phần tử thỏa mãn điều kiện.

Ví dụ sau đây minh họa phương thức SingleOrDefault:

IList<int> oneElementList = new List<int>() { 7 };
IList<int> intList = new List<int>() { 7, 10, 21, 30, 45, 50, 87 };
IList<string> strList = new List<string>() { null, "Two", "Three", "Four", "Five" };
IList<string> emptyList = new List<string>();

Console.WriteLine("The only element in oneElementList: {0}", oneElementList.SingleOrDefault());
Console.WriteLine("The only element which is less than 10 in intList: {0}",
             intList.SingleOrDefault(i => i < 10));

Console.WriteLine("The only element in emptyList: {0}", emptyList.SingleOrDefault());

Đây là kết quả khi biên dịch và thực thi chương trình:

The only element in oneElementList: 7
The only element in oneElementList: 7
Element in emptyList: 0
Tip: nên sử dụng phương thức mở rộng SingleOrDefault thay thế cho phương thức Single để loại trừ khả năng xảy ra ngoại lệ thời gian chạy.

Sự khác nhau giữa phương thức First và Single

Phương thức First

Phương thức First trả về phần tử đầu tiên của danh sách hoặc phần tử đầu tiên thỏa mãn điều kiện đã chỉ định bằng biểu thức lambda hoặc delegate Func.

Nếu có nhiều phần tử thỏa mãn điều kiện đã chỉ định thì nó sẽ trả về phần tử đầu tiên.

Nếu một danh sách rỗng hoặc không có bất kỳ phần tử nào thỏa mãn điều kiện thì nó sẽ ném ra ngoại lệ InvalidOperation.

Phương thức Single

Phương thức Single trả về phần tử duy nhất của danh sách hoặc phần tử duy nhất thỏa mãn điều kiện đã chỉ định bằng biểu thức lambda hoặc delegate Func.

Nếu một danh sách rỗng hoặc không có bất kỳ phần tử nào thỏa mãn điều kiện hoặc có nhiều hơn một phần tử thỏa mãn điều kiện thì nó sẽ ném ra ngoại lệ InvalidOperation.



Bài viết liên quan:

Bạn sẽ tìm hiểu một số truy vấn LINQ phức tạp trong hướng dẫn này.

Từ khóa let, into trong LINQ có tác dụng gì? Hướng dẫn khai báo và sử dụng từ khóa let, into trong LINQ.

Trì hoãn thực thi truy vấn LINQ là gì? Thực thi ngay lập tức truy vấn LINQ là gì? Làm sao để thực thi truy vấn LINQ.