Toán tử tập hợp trong LINQ

Bảng sau liệt kê tất cả các toán tử tập hợp có sẵn trong LINQ.

Phương thức Mô tả
Distinct Trả về các phần tử khác nhau từ một danh sách.
Except Trả về các phần tử của một danh sách không xuất hiện trong danh sách thứ hai.
Intersect Trả về giao của hai danh sách, có nghĩa là các phần tử cùng xuất hiện trong cả hai danh sách.
Union Trả về các phần tử duy nhất từ hai danh sách, có nghĩa là các phần tử duy nhất xuất hiện ở một trong hai danh sách.

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>.

Hình dưới đây minh họa cách mỗi toán tử tập hợp hoạt động trên các bộ sưu tập:

Các toán tử tập hợp trong LINQ

Phương thức Distinct trong LINQ

Phương thức mở rộng Distinct trả về một tập hợp các phần tử duy nhất từ ​​danh sách đã cho.

Ví dụ dưới đây minh họa sử dụng phương thức Distinct trong LINQ:


IList<string> strList = new List<string>() { "One", "Two", "Three", "Two", "Three" };

IList<int> intList = new List<int>() { 1, 2, 3, 2, 4, 4, 3, 5 };

var distinctList1 = strList.Distinct();
foreach(var str in distinctList1)
{
    Console.WriteLine(str);
}

var distinctList2 = intList.Distinct();
foreach(var i in distinctList2)
{
    Console.WriteLine(i);
}

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

One
Two
Three
1
2
3
4
5

Phương thức mở rộng Distinct không so sánh giá trị của các đối tượng kiểu phức tạp. Bạn cần triển khai interface IEqualityComparer<T> để so sánh giá trị của các kiểu phức tạp.

Trong ví dụ sau, lớp StudentComparer triển khai interface IEqualityComparer<Student> để so sánh các đối tượng Student trong danh sách.

public class Student 
{
    public int StudentID { get; set; }
    public string StudentName { get; set; }
    public int Age { get; set; }
}

class StudentComparer : IEqualityComparer<Student>
{
    public bool Equals(Student x, Student y)
    {
        return x.StudentID == y.StudentID &&
            x.StudentName.ToLower() == y.StudentName.ToLower();
    }

    public int GetHashCode(Student obj)
    {
        return obj.StudentID.GetHashCode();
    }
}

Bây giờ, bạn có thể truyền một đối tượng của lớp StudentComparer trên làm tham số trong phương thức Distinct để so sánh các đối tượng Student như dưới đây.

Ví dụ dưới đây minh họa sử dụng lớp StudentComparer làm đối số cho phương thức Distinct trong LINQ:

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 = 3, StudentName = "Bill", Age = 25 },
    new Student() { StudentID = 3, StudentName = "Bill", Age = 25 },
    new Student() { StudentID = 3, StudentName = "Bill", Age = 25 },
    new Student() { StudentID = 5, StudentName = "Ron" , Age = 19 } 
};

var distinctStudents = studentList.Distinct(new StudentComparer());
foreach(Student std in distinctStudents)
{
    Console.WriteLine(std.StudentName);
}

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

John
Steve
Bill
Ron
Lưu ý: Phương thức mở rộng Distinct không hỗ trợ  cú pháp truy vấn trong LINQ.

Phương thức Except trong LINQ

Phương thức mở rộng Except yêu cầu đầu vào là hai danh sách. Nó trả về một danh sách mới với các phần tử từ danh sách đầu tiên không tồn tại trong danh sách thứ hai.

Ví dụ dưới đây minh họa sử dụng phương thức Except trong LINQ:


IList<string> strList1 = new List<string>() {"One", "Two", "Three", "Four", "Five" };
IList<string> strList2 = new List<string>() {"Four", "Five", "Six", "Seven", "Eight"};

var result = strList1.Except(strList2);
foreach(string str in result)
{
    Console.WriteLine(str);
}

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

One
Two
Three

Tương tự như phương thức Distinct, phương thức mở rộng Except cũng không trả về kết quả chính xác cho các danh sách có kiểu phức tạp. Bạn cần triển khai interface IEqualityComparer<T> để có được kết quả chính xác khi sử dụng phương thức Except.

Bạn có thể sử dụng lại lớp StudentComparer được định nghĩa ở phương thức Distinct cho phương thức mở rộng Except để có kết quả chính xác.

Ví dụ dưới đây minh họa sử dụng lớp StudentComparer làm đối số cho phương thức Except trong LINQ:

IList<Student> studentList1 = 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 = 5, StudentName = "Ron" , Age = 19 } 
};

IList<Student> studentList2 = new List<Student>() 
{ 
    new Student() { StudentID = 3, StudentName = "Bill", Age = 25 },
    new Student() { StudentID = 5, StudentName = "Ron" , Age = 19 } 
};

var resultedCol = studentList1.Except(studentList2, new StudentComparer());
foreach(Student std in resultedCol)
{
    Console.WriteLine(std.StudentName);
}

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

John
Steve
Lưu ý: Phương thức mở rộng Except không hỗ trợ  cú pháp truy vấn trong LINQ.

Phương thức Intersect trong LINQ

Phương thức mở rộng Intersect yêu cầu đầu vào là hai danh sách. Nó trả về một danh sách mới với các phần tử tồn tại trong cả hai danh sách.

Ví dụ dưới đây minh họa sử dụng phương thức Intersect trong LINQ:


IList<string> strList1 = new List<string>() {"One", "Two", "Three", "Four", "Five" };
IList<string> strList2 = new List<string>() {"Four", "Five", "Six", "Seven", "Eight"};

var result = strList1.Intersect(strList2);
foreach(string str in result)
{
    Console.WriteLine(str);
}

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

Four
Five

Tương tự như phương thức Distinct và Except, phương thức mở rộng Intersect cũng không trả về kết quả chính xác cho các danh sách có kiểu phức tạp. Bạn cần triển khai interface IEqualityComparer<T> để có được kết quả chính xác khi sử dụng phương thức Intersect.

Bạn có thể sử dụng lại lớp StudentComparer được định nghĩa ở phương thức Distinct cho phương thức mở rộng Intersect để có kết quả chính xác.

Ví dụ dưới đây minh họa sử dụng lớp StudentComparer làm đối số cho phương thức Intersect trong LINQ:

IList<Student> studentList1 = 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 = 5, StudentName = "Ron" , Age = 19 } 
};

IList<Student> studentList2 = new List<Student>() 
{ 
    new Student() { StudentID = 3, StudentName = "Bill", Age = 25 },
    new Student() { StudentID = 5, StudentName = "Ron" , Age = 19 } 
};

var resultedCol = studentList1.Intersect(studentList2, new StudentComparer());
foreach(Student std in resultedCol)
{
    Console.WriteLine(std.StudentName);
}

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

Bill
Ron
Lưu ý: Phương thức mở rộng Intersect không hỗ trợ  cú pháp truy vấn trong LINQ.

Phương thức Union trong LINQ

Phương thức mở rộng Union yêu cầu đầu vào là hai danh sách. Nó trả về một danh sách mới với các phần tử khác nhau ở trong cả hai danh sách.

Ví dụ dưới đây minh họa sử dụng phương thức Union trong LINQ:


IList<string> strList1 = new List<string>() {"One", "Two", "Three", "Four", "Five", "Six" };
IList<string> strList2 = new List<string>() {"Four", "Five", "Six", "Seven", "Eight"};

var result = strList1.Union(strList2);
foreach(string str in result)
{
    Console.WriteLine(str);
}

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

One
Two
Three
Four
Five
Six
Seven
Eight

Tương tự như phương thức Distinct, Except và Intersect, phương thức mở rộng Union cũng không trả về kết quả chính xác cho các danh sách có kiểu phức tạp. Bạn cần triển khai interface IEqualityComparer<T> để có được kết quả chính xác khi sử dụng phương thức Union.

Bạn có thể sử dụng lại lớp StudentComparer được định nghĩa ở phương thức Distinct cho phương thức mở rộng Union để có kết quả chính xác.

Ví dụ dưới đây minh họa sử dụng lớp StudentComparer làm đối số cho phương thức Union trong LINQ:

IList<Student> studentList1 = 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 = 5, StudentName = "Ron" , Age = 19 } 
};

IList<Student> studentList2 = new List<Student>() 
{ 
    new Student() { StudentID = 3, StudentName = "Bill", Age = 25 },
    new Student() { StudentID = 5, StudentName = "Ron" , Age = 19 },
    new Student() { StudentID = 6, StudentName = "July" , Age = 18 }  
};

var resultedCol = studentList1.Union(studentList2, new StudentComparer());
foreach(Student std in resultedCol)
{
    Console.WriteLine(std.StudentName);
}

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

John
Steve
Bill
Ron
July
Lưu ý: Phương thức mở rộng Union không hỗ trợ  cú pháp truy vấn 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.