Các toán tử truy vấn chuẩn là các phương thức hình thành các mẫu (pattern) LINQ. Đa số các phương thức này hoạt động trên các tập dữ liệu, với 1 tập dữ liệu là 1 đối tượng có kiểu dữ liệu là giao diện IEnumerable<T> hay giao diện IQueryable<T>. Các toán tử truy vấn chuẩn cung cấp các khả năng truy vấn bao gồm lọc, tham chiếu, kết hợp, sắp xếp và nhiều chức năng khác. Có 2 cách thực thi các toán tử truy vấn chuẩn đó là: ngay lập tức (immediate) và trì hoãn (deferred).
- Ngay lập tức
Thực thi ngay lập tức nghĩa là khi câu truy vấn được khai báo thì nguồn dữ liệu cũng được truy xuất và toán tử cũng được thực hiện. Tất cả các toán tử truy vấn chuẩn trả về kết quả đơn (single) hoặc không đếm được đều thực thi ngay lập tức. - Trì hoãn
Thực thi trì hoãn nghĩa là toán tử sẽ không thực hiện tại lúc câu truy vấn được khai báo. Toán tử thực hiện chỉ khi biến truy vấn được liệt kê, ví dụ bằng cách dùng vòng lặp foreach. Điều này có nghĩa là kết quả thực thi câu truy vấn phụ thuộc vào nội dung dữ liệu nguồn khi truy vấn được thực thi hơn là truy vấn được định nghĩa. Nếu biến truy vấn được liệt kê nhiều lần, các kết quả có thể khác nhau giữa các lần đó. Đa số tất cả các toán tử truy vấn chuẩn có kiểu trả về là IEnumerable<T> hoặc IOrderedEnumerable<TElement> trong ngữ cảnh trì hoãn.
1. Sắp xếp dữ liệu
Toán tử sắp xếp sắp xếp các phần tử trong 1 tập dữ liệu dựa trên 1 hay nhiều thuộc tính. Tiêu chí sắp xếp đầu tiên là chủ yếu sắp theo các phần tử. Bằng cách đặc tả tiêu chí sắp xếp thứ hai, chúng ta có thể sắp xếp các phần tử bên trong mỗi nhóm sắp xếp chính.
Các phương thức sắp xếp chuẩn được mô tả trong bảng sau:
Tên phương thức | Mô tả | Cú pháp diễn giải truy vấn C# |
---|---|---|
OrderBy | Sắp xếp giá trị theo thứ tăng dần | orderby |
OrderByDescending | Sắp xếp giá trị theo thứ tự giảm dần | orderby … descending |
ThenBy | Thực hiện sắp xếp phụ theo thứ tự tăng dần | orderby …, … |
ThenByDescending | Thực hiện sắp xếp phụ theo thứ tự giảm dần | orderby …, … descending |
Reverse | Đảo ngược thứ tự | không áp dụng |
Ví dụ 1: Sắp xếp các từ theo thứ tự tăng dần độ dài của từ.
// www.dammio.com string[] words = { "xin", "chào", "mọi", "người", "nhé" }; IEnumerable<string> query = from word in words orderby word.Length select word; foreach (string str in query) Console.WriteLine(str); // hiển thị giá trị mỗi lần phần tử /* Đoạn mã cho ra kết quả: xin mọi nhé chào người */
Ví dụ 2: Sắp xếp giảm dần các từ trong mảng theo chữ cái đầu tiên của từ.
// www.dammio.com string[] words = { "xin", "chào", "mọi", "người", "nhé" }; IEnumerable<string> query = from word in words orderby word.Substring(0, 1) descending select word; foreach (string str in query) Console.WriteLine(str); /* Đoạn mã cho ra kết quả: xin người nhé mọi chào */
Ví dụ 3: Sắp xếp tăng dần theo độ dài của từ, sau đó giảm dần theo chữ cái đầu tiên của từ
// www.dammio.com string[] words = { "xin", "chào", "mọi", "người", "nhé" }; IEnumerable<string> query = from word in words orderby word.Length, word.Substring(0, 1) descending select word; // orderby word.Length không khai báo gì cả thì mặc định là ascending (sắp tăng) foreach (string str in query) Console.WriteLine(str); /* Đoạn mã cho ra kết quả: xin nhé mọi chào người */
2. Toán tử tập hợp
Toán tử tập hợp trong LINQ là các toán tử truy vấn sinh ra 1 tập kết quả dựa trên sự có mặt hoặc vắng mặt của các phần tử tương đương bên trong các tập hợp giống nhau hoặc tách rời. Các phương thức toán tử truy vấn chuẩn thực thi các toán tử tập hợp được liệt kê trong bảng sau:
Tên phương thức | Mô tả | Cú pháp diễn giải truy vấn C# |
---|---|---|
Distinct | Bỏ các kết quả trùng lặp trong 1 tập hợp | không áp dụng |
Except | Trả về các phần tử của 1 tập mà không xuất hiện trong tập thứ 2 | không áp dụng |
Intersect | Trả về một tập giao những phần tử xuất hiện trong 2 tập cho trước | không áp dụng |
Union | Trả về tập hợp nhất của 2 tập, tập những phần tử phải ít nhất thuộc về 1 trong 2 tập | không áp dụng |
Ví dụ 1: Loại bỏ các số trùng nhau trong 1 mảng số
// www.dammio.com int[] numbers = { 6, 77, 6, 1, 9, 11, 11, 18, 9 }; // Loại bỏ các phần tử trùng nhau IEnumerable<int> query = (from num in numbers select num).Distinct(); //Cách 2: IEnumerable<int> query = numbers.Distinct(); foreach (string str in query) Console.WriteLine(str); /* Đoạn mã cho ra kết quả: 6 77 1 9 11 18 */
Ví dụ 2: Tìm phần tử chung giữa 2 tập hợp numbers1 và numbers2
// www.dammio.com int[] numbers1 = { 6, 77, 6, 1, 9, 11, 11, 18, 9 }; int[] numbers2 = { 6, 8, 77, 12, 18, 7 }; // Loại bỏ các phần tử trùng nhau IEnumerable<int> query = (from num1 in numbers1 select num1).Intersect(from num2 in numbers2 select num2); // Cách 2: IEnumerable<int> query = numbers1.Intersect(numbers2); // Cách 3: IEnumerable<int> query = numbers1.Select(x => x).Intersect(numbers2.Select(x => x)); foreach (int item in query) Console.WriteLine(item); /* Đoạn mã cho ra kết quả: 6 77 18 */
Ví dụ 3: Kết quả hợp nhất (union) của 2 tập hợp cho trước
// www.dammio.com int[] numbers1 = { 6, 77, 6, 1, 9, 11, 11, 18, 9 }; int[] numbers2 = { 6, 8, 77, 12, 18, 7 }; // Hợp nhất các phần tử của 2 tập hợp Enumerable<int> query = numbers1.Union(numbers2); // Các cách khác tương tự phần Intersect foreach (int item in query) Console.WriteLine(item); /* Đoạn mã cho ra kết quả: 6 77 1 9 11 18 8 12 7 */
3. Lọc dữ liệu
Lọc dữ liệu là toán tử hạn chế tập kết quả chỉ chứa các phần tử thỏa mãn theo yêu cầu nào đó cho trước. Chúng ta cũng có thể gọi đây là quá trình chọn lọc (selection). Các phương thức toán tử truy vấn chuẩn để thực thi việc lọc dữ liệu được liệt kê trong bảng sau:
Tên phương thức | Mô tả | Cú pháp diễn giải truy vấn C# |
---|---|---|
OfType | Chọn các giá trị, tùy theo khả năng chuyển kiểu dữ liệu của nó sang 1 kiểu dữ liệu nào đó. | không áp dụng |
Where | Chọn các giá trị dựa trên các điều kiện cho trước | where |
Ví dụ 1: Lọc các phần tử trong ArrayList là kiểu chuỗi bằng phương thức OfType()
// www.dammio.com System.Collections.ArrayList items = new System.Collections.ArrayList(4); items.Add("Shoes"); items.Add("Clothes"); items.Add(15.5); // kiểu số // Áp dụng OfType() vào ArrayList để tìm các phần tử là kiểu chuỗi IEnumerable<string> query1 = items.OfType<string>(); // Xuất danh sách các phần tử kiểu chuỗi trong 1 ArrayList foreach (string item in query1) Console.WriteLine(item); /* Đoạn mã cho ra kết quả: Shoes Clothes */
Ví dụ 2: Tìm những số lớn hơn 5 và bé hơn 10 trong danh sách các số cho trước.
// www.dammio.com int[] numbers1 = { 6, 77, 6, 1, 9, 11, 11, 18, 9 }; // Hợp nhất các phần tử của 2 tập hợp IEnumerable<int> query = from num in numbers1 where num > 5 && num < 10 select num; foreach (int item in query) Console.WriteLine(item); /* Đoạn mã cho ra kết quả: 6 6 9 9 */
4. Toán tử lượng hóa
Toán tử lượng hóa trả về giá trị Bool chỉ ra khi nào một vài hoặc toàn bộ phần tử trong 1 tập dữ liệu thỏa mãn điều kiện. Các phương thức toán tử truy vấn chuẩn thực thi các toán tử lượng hóa được liệt kê trong bảng sau.
Tên phương thức | Mô tả | Cú pháp diễn giải truy vấn C# |
---|---|---|
All | Xác định khi nào tất cả các phần tử trong 1 tập dữ liệu thỏa mãn yêu cầu nào đó. | không áp dụng |
Any | Xác định khi nào bất kỳ phần tử nào trong tập dữ liệu thỏa mãn yêu cầu nào đó. | không áp dụng |
Contains | Xác định khi nào 1 tập dữ liệu chứa 1 phần tử nào đó. | không áp dụng |
Ví dụ 1: Kiểm tra tất cả các tên trong danh sách có bắt đầu bằng vần A
// www.dammio.com List<string> listNames = new List<string>() { "Adam", "Adar", "Anderson", "Bob" }; // Kiểm tra tất cả các tên bắt đầu bằng vần A hay không? bool result = listNames.All(x => x.StartsWith("A")); Console.WriteLine("All names start with letter A? " + result); /* Đoạn mã cho ra kết quả: All names start with letter A? False */
Ví dụ 2: Kiểm tra xem ít nhất có 1 tên bắt đầu bằng vần B hay không?
// www.dammio.com List<string> listNames = new List<string>() { "Adam", "Adar", "Anderson", "Bob" }; // Kiểm tra xem ít nhất có 1 tên bắt đầu bằng vần B hay không? bool result = listNames.Any(x => x.StartsWith("B")); Console.WriteLine("Any names start with letter B? " + result); /* Đoạn mã cho ra kết quả: Any names start with letter B? True */
Ví dụ 3: Kiểm tra xem các tên trong danh sách có chứa phần tử “ada” hay không?
// www.dammio.com List<string> listNames = new List<string>() { "Adam", "Adar", "Anderson", "Bob" }; // Kiểm tra xem các tên có chứa phần tử "ada" hay không bool result = listNames.Contains("ada"); // Kết quả Console.WriteLine("Names contain \"ada\"? " + result); /* Đoạn mã cho ra kết quả: Names contain "ada"? False */
Ví dụ 4: Tìm các tên có chứa chuỗi “Ada” và trường hợp phân biệt hoa thường
// www.dammio.com List<string> listNames = new List<string>() { "Adam", "Adar", "Anderson", "adart", "Bob" }; // Tìm danh sách tên có chứa chuỗi "Ada" (A hoa) var query = from name in listNames where name.Contains("Ada") select name; // Tìm danh sách tên có chứa chuỗi "Ada", tính cả hoa thường (A và a) string x = "Ada"; var query1 = from name in listNames where name.ToLower().Contains(x.ToLower()) select name; // Kết quả query foreach(var item in query) Console.WriteLine(item); // Kết quả query1 foreach (var item1 in query1) Console.WriteLine(item1); /* Đoạn mã cho ra kết quả: Adam Adar Adam Adar adart */
5. Toán tử tham chiếu
Tham chiếu (projection) là toán tử chuyển đổi 1 đối tượng thành 1 dạng mới mà thường chỉ chứa các thuộc tính thường dùng. Bằng cách dùng tham chiếu, chúng ta có thể xây dựng 1 dạng mới được xây dựng cho mỗi dự án. Chúng ta có thể tham chiếu 1 thuộc tính và thực thi 1 hàm toán học trên thuộc tính đó. Bạn cũng có thể tham chiếu 1 đối tượng gốc mà không cần thay đổi gì đối tượng này hết. Các phương thức toán tử truy vấn chuẩn thực thi việc tham chiếu được liệt kê trong bảng sau.
Tên phương thức | Mô tả | Cú pháp diễn giải truy vấn C# |
---|---|---|
Select | Tham chiếu các giá trị dựa vào 1 hàm chuyển đổi. | select |
SelectMany | Tham chiếu các tập dữ liệu giá trị dựa trên 1 hàm chuyển đổi sau đó chia các tập này thành 1 tập đơn. | dùng nhiều mệnh đề from |
Ví dụ 1: Lấy chữ cái đầu của 1 danh sách kiểu string.
// www.dammio.com List<string> names = new List<string>() { "welcome", "to", "dammio", "dot", "com" }; // Lấy chữ cái đầu của từng phần tử var query = from name in names select name.Substring(0, 1); foreach (string s in query) Console.WriteLine(s); /* Đoạn mã cho ra kết quả: w t d d c */
Ví dụ 2: Sử dụng nhiều mệnh đề from để tách cụm từ thành từng từ (SelectMany)
// www.dammio.com List<string> names = new List<string>() { "welcome to", "dammio dot com" }; // Lấy chữ cái đầu của từng phần tử var query = from name in names from word in name.Split(' ') select word; foreach (string s in query) Console.WriteLine(s); /* Đoạn mã cho ra kết quả: welcome to dammio dot com */
Ví dụ 3: Cách dùng Select và SelectMany để lấy dữ liệu từ tập dữ liệu nguồn
class Categories // Lớp Categories chứa danh sách các sản phẩm { public List<string> Products { get; set; } } static void Test() { // www.dammio.com List<Categories> list = new List<Categories>() { new Categories{Products = new List<string> {"clothes","shoes","jean","water"}}, new Categories{Products = new List<string> {"mobile","sim","laptop","ipad"}}, }; // Select IEnumerable<List<string>> query1 = list.Select(x => x.Products); // SelectMany IEnumerable<string> query2 = list.SelectMany(x => x.Products); Console.WriteLine("Kết quả khi dùng Select(): "); foreach (IEnumerable<String> collection in query1) foreach (string item in collection) Console.WriteLine(item); Console.WriteLine("\nKết quả khi dùng SelectMany(): "); foreach (string item in query2) Console.WriteLine(item); /* Đoạn mã cho ra kết quả: Kết quả khi dùng Select(): clothes shoes jean water mobile sim laptop ipad Kết quả khi dùng SelectMany(): clothes shoes jean water mobile sim laptop ipad */ }
Như vậy bài này trình bày cho các bạn 1 số toán tử trong LINQ. Bài tiếp theo sẽ tiếp tục trình bày cho các bạn về các toán tử truy vấn chuẩn trong LINQ, mời các bạn theo dõi.