Toán tử lọc của LINQ

Các toán tử filtering trong LINQ lọc danh sách dựa trên một số tiêu chí đã được định nghĩa. Bảng sau liệt kê tất cả toán tử lọc có sẵn trong LINQ.

Toán tử Mô tả
Where Trả về các phần tử từ danh sách dựa trên biểu thức điều kiện.
OfType Trả về các phần tử từ danh sách dựa trên một kiểu được chỉ định. Tuy nhiên, nó sẽ phụ thuộc vào khả năng của chúng để chuyển sang một kiểu cụ thể.

Toán tử lọc 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>.

Toán tử lọc Where trong LINQ

Toán tử Where (một phương thức mở rộng của LINQ) lọc danh sách dựa trên biểu thức điều kiện đã cho và trả về danh sách mới. Các điều kiện có thể là biểu thức lambda hoặc delegate Func.

Phương thức mở rộng Where sau có hai phương thức quá tải. Cả hai phương thức quá tải đều chấp nhận tham số kiểu delegate Func.

Phương thức quá tải đầu tiên yêu cầu tham số đầu vào là Func<TSource, bool> và phương thức quá tải thứ hai yêu cầu tham số đầu vào Func<TSource, int, bool> trong đó int là chỉ mục:

// first
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate);
// second
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, int, bool> predicate);

Mệnh đề where trong cú pháp truy vấn LINQ

Mẫu truy vấn sau đây sử dụng toán tử Where để lọc các học sinh tuổi teen (từ 13 - 19 tuổi) từ danh sách học sinh đã cho. Nó sử dụng biểu thức lambda như một hàm vị ngữ.

// Student collection
IList<Student> studentList = new List<Student>() 
{ 
	new Student() { StudentID = 1, StudentName = "John", Age = 13 },
	new Student() { StudentID = 2, StudentName = "Moin",  Age = 21 },
	new Student() { StudentID = 3, StudentName = "Bill",  Age = 18 },
	new Student() { StudentID = 4, StudentName = "Ram", Age = 20 },
	new Student() { StudentID = 5, StudentName = "Ron", Age = 15 } 
};

// LINQ Query Syntax to find out teenager students
var teenAgerStudent = from s in studentList
                      where s.Age > 12 && s.Age < 20
                      select s;
				  
foreach(Student std in teenAgerStudent)
{			
	Console.WriteLine(std.StudentName);
}

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

John
Bill
Ron

Trong truy vấn mẫu ở trên, phần thân biểu thức lambda s.Age > 12 && s.Age < 20 được truyền dưới dạng hàm vị ngữ Func<TSource, bool> để đánh giá mọi học sinh trong danh sách.

Ngoài ra, bạn cũng có thể sử dụng kiểu delegate Func với phương thức ẩn danh để truyền vào dưới dạng hàm vị ngữ như bên dưới (kết quả trả về đều giống nhau):

Func<Student, bool> isTeenAger = delegate(Student s) 
{ 
    return s.Age > 12 && s.Age < 20; 
};

var filteredResult = from s in studentList
                     where isTeenAger(s)
                     select s;

Bạn cũng có thể gọi bất kỳ phương thức nào khớp với tham số Func cho một trong các phương thức Where() quá tải như ví dụ dưới đây:

public static void Main()
{
    var filteredResult = from s in studentList
                         where IsTeenAger(s)
                         select s;
}

public static bool IsTeenAger(Student student)
{
    return student.Age > 12 && student.Age < 20;  
}

Phương thức Where trong cú pháp phương thức LINQ

Không giống như cú pháp truy vấn, bạn cần truyền toàn bộ biểu thức lambda dưới dạng hàm vị ngữ thay vì chỉ có phần thân biểu thức trong cú pháp phương thức LINQ. Hãy xem ví dụ sau:

// Where extension method in Method Syntax
var filteredResult = studentList.Where(s => s.Age > 12 && s.Age < 20);

Như đã đề cập ở trên, phương thức mở rộng Where cũng có phương thức quá tải thứ hai bao gồm chỉ mục của phần tử hiện tại trong danh sách. Bạn có thể sử dụng chỉ mục đó trong logic của bạn nếu bạn cần.

Ví dụ sau sử dụng phương thức mở rộng Where để lọc ra các phần tử ở vị trí lẻ trong danh sách và chỉ trả về các phần tử ở vị trí chẵn. Hãy nhớ rằng chỉ số bắt đầu từ số 0.

IList<Student> studentList = new List<Student>() 
{ 
    new Student() { StudentID = 1, StudentName = "John", Age = 18 },
    new Student() { StudentID = 2, StudentName = "Steve",  Age = 15 },
    new Student() { StudentID = 3, StudentName = "Bill",  Age = 25 },
    new Student() { StudentID = 4, StudentName = "Ram" , Age = 20 },
    new Student() { StudentID = 5, StudentName = "Ron" , Age = 19 } 
};

var filteredResult = studentList.Where((s, index) => index % 2 == 0);

foreach (var student in filteredResult)
{
    Console.WriteLine(student.StudentName);
}

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

John
Bill
Ron

Nhiều mệnh đề where

Bạn có thể gọi mệnh đề where nhiều lần trong một truy vấn LINQ sử dụng cú pháp truy vấn.

// Multiple where clause in Query Syntax C#
var filteredResult = from s in studentList
                     where s.Age > 12
                     where s.Age < 20
                     select s;

Bạn cũng có thể gọi phương thức mở rộng Where() nhiều lần trong một truy vấn LINQ sử dụng cú pháp phương thức.

// Multiple where clause in Method Syntax C#
var filteredResult = studentList.Where(s => s.Age > 12)
                                .Where(s => s.Age < 20);

Khi sử dụng nhiều mệnh đề where thì LINQ lọc danh sách kết quả theo thứ tự của các mệnh đề where.

Như ở ví dụ trên, đầu tiên LINQ sẽ lọc ra những học sinh có tuổi lớn hơn 12 sau đó nó tiếp tục lấy những sinh viên đã được lọc ở mệnh đề where đầu tiên để lấy ra những sinh viên có tuổi nhỏ hơn 20.

Hai mệnh đề where trên tương đương với biểu thức sau: where s.Age > 12 && s.Age < 20 hoặc Where(s => s.Age > 12 && s.Age < 20).

Những điểm cần nhớ về toán tử Where:

  1. Where được sử dụng để lọc danh sách dựa trên các tiêu chí nhất định.
  2. Phương thức mở rộng Where có hai phương thức quá tải. Sử dụng phương thức  quá tải thứ hai để biết chỉ mục của phần tử hiện tại trong danh sách.
  3. Cú pháp phương thức LINQ yêu cầu toàn bộ biểu thức lambda trong phương thức mở rộng Where trong khi cú pháp truy vấn chỉ yêu cầu phần thân biểu thức lambda.
  4. Có thể sử dụng nhiều mệnh đề where hoặc phương thức mở rộng Where trong một truy vấn LINQ duy nhất.

Toán tử lọc OfType trong LINQ

Toán tử OfType lọc danh sách dựa trên khả năng ép kiểu một phần tử trong danh sách thành kiểu được định.

Toán tử OfType trong cú pháp truy vấn LINQ

Sử dụng toán tử OfType để lọc danh sách dựa trên kiểu dữ liệu của từng phần tử.

IList mixedList = new ArrayList();
mixedList.Add(0);
mixedList.Add("One");
mixedList.Add("Two");
mixedList.Add(3);
mixedList.Add(new Student() { StudentID = 1, StudentName = "Bill" });

var stringResult = from s in mixedList.OfType<string>()
                   select s;

var intResult = from s in mixedList.OfType<int>()
                select s;

var stdResult = from s in mixedList.OfType<Student>()
                select s;

foreach (var str in stringResult)
{
	Console.WriteLine(str);
}

foreach (var integer in intResult)
{
	Console.WriteLine(integer);
}

foreach (var std in stdResult)
{
	Console.WriteLine(std.StudentName);
}

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

One
Two
0
3
Bill

Phương thức mở rộng OfType trong cú pháp phương thức LINQ.

Bạn có thể sử dụng phương thức mở rộng OfType<TResult>() trong cú pháp phương thức LINQ như bên dưới:

var stringResult = mixedList.OfType<string>();

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

One
Two

Những điểm cần nhớ về toán tử OfType trong LINQ

  1. Toán tử OfType lọc danh sách dựa trên một kiểu dữ liệu được chỉ định.
  2. Các phương thức mở rộng OfType có thể được gọi nhiều lần trong một truy vấn LINQ.

Truy cập MSDN để biết thêm thông tin về các toán tử filtering trong LINQ.



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.