[LINQ] Phần 8: Các toán tử truy vấn chuẩn trong LINQ 1

1.603 lượt xem

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.

Bình luận Facebook

Để lại bình luận

1 Comment on "[LINQ] Phần 8: Các toán tử truy vấn chuẩn trong LINQ 1"

Notify of
avatar
1000
Sort by:   newest | oldest | most voted
trackback

[…] Any / All, Contains, Count. Cách dùng các toán tử này mời bạn xem ở bài viết: Các toán tử truy vấn chuẩn 1, Các toán tử truy vấn chuẩn 2, Các toán tử truy vấn chuẩn […]

wpDiscuz