[C#] 進階 - LINQ 標準查詢操做概述

LINQ 標準查詢操做概述     

 

序 

  「標準查詢運算符」是組成語言集成查詢 (LINQ) 模式的方法。大多數這些方法都在序列上運行,其中的序列是一個對象,其類型實現了 IEnumerable<T> 接口或  IQueryable<T> 接口。標準查詢運算符提供了包括 篩選、投影、聚合、排序等功能在內的查詢功能。  
     各個標準查詢運算符在 執行時間上有所不一樣,具體狀況取決於它們是返回 單一值仍是 值序列。返回單一值的方法(例如  Average 和  Sum)會 當即執行。返回序列的方法會 延遲查詢執行,並返回一個可枚舉的對象。  
     對於在內存中集合上運行的方法(即擴展  IEnumerable<T> 的方法),返回的可枚舉對象將捕獲傳遞到方法的參數。在枚舉該對象時,將使用查詢運算符的邏輯,並返回查詢結果。  
      與之相反,擴展  IQueryable<T> 的方法 不會實現任何查詢行爲,但 會生成一個表示要執行的查詢的 表達式樹。查詢處理由源  IQueryable<T> 對象處理。
 

1、按標準執行方式分類

     標準查詢運算符方法的 LINQ to Objects 實現採用兩種主要方式之一來執行: 當即執行延遲執行。採用延遲執行的查詢運算符能夠進一步分爲兩類: 流式非流式
     
     1.執行方式
          (1) 當即: 當即執行意味着在代碼中聲明查詢的位置讀取數據源並執行運算。   返回單個不可枚舉的結果的全部標準查詢運算符都當即執行
          (2) 延遲: 延遲執行意味着不在代碼中聲明查詢的位置執行運算。   僅當對查詢變量進行枚舉操做時才執行運算,例如經過使用  foreach 語句。這意味着查詢的執行結果 取決於執行查詢而非定義查詢時的數據源內容。若是屢次枚舉查詢變量,則每次結果可能都不一樣。幾乎全部返回類型爲  IEnumerable<T> 或  IOrderedEnumerable<TElement> 的標準查詢運算符都以延遲方式執行。 
           採用延遲執行方式的查詢運算符能夠另外分類爲 流式非流式
          ① 流式運算符不須要在生成元素前讀取全部源數據。在執行時,流式運算符一邊讀取每一個源元素,一邊對該源元素執行運算,並在可行時生成元素。流式運算符將持續讀取源元素直到能夠生成結果元素。這意味着可能要讀取多個源元素才能生成一個結果元素。
          ② 非流式運算符必須讀取全部源數據才能生成結果元素。諸如 排序分組等運算屬於此類別。在執行時,非流式查詢運算符讀取全部源數據,將其放入數據結構中,執行運算,而後生成結果元素。
 

2、排列數據

     排序操做按一個或多個特性對序列的元素進行排序。第一個排序條件對元素執行主要排序。經過指定第二個排序條件,能夠對各個主要排序組中的元素進行排序。 
     下圖演示對一個字符序列執行按字母排序操做的結果。
  

 

標準查詢運算符操做方法 - 排序
方法名 說明 C# 查詢表達式語法
OrderBy 按升序對值進行排序。 orderby
OrderByDescending 按降序對值進行排序。 orderby … descending
ThenBy 按升序執行次要排序。 orderby …, …
ThenByDescending 按降序執行次要排序。 orderby …, … descending
Reverse 顛倒集合中的元素的順序。 X

  

  示例:html

1 var words = new[] { "the", "quick", "brown", "fox", "jumps" };
2 var query = from word in words
3                    orderby word.Length
4                    select word;
5 
6 foreach (var word in query)
7 {
8     Console.WriteLine(word);
9 }
下面經過演示使用 orderby 進行升序排序:按字符串長度

 

 

1 var words = new[] { "the", "quick", "brown", "fox", "jumps" };
2 var query = from word in words
3                    orderby word.Substring(0,1) descending 
4                    select word;
5 
6 foreach (var word in query)
7 {
8     Console.WriteLine(word);
9 }
下面經過演示使用 orderby descending 進行降序排序:按字符串的第一個字母

 

1 var words = new[] { "the", "quick", "brown", "fox", "jumps" };
2 var query = from word in words
3                    orderby word.Length, word.Substring(0, 1)
4                    select word;
5 
6 foreach (var word in query)
7 {
8     Console.WriteLine(word);
9 }
下面經過演示使用 orderby 進行主要和次要排序:先升序按字符串長度(主)、再升序按字符串的第一個字母(次)

 

1 var words = new[] { "the", "quick", "brown", "fox", "jumps" };
2 var query = from word in words
3                    orderby word.Length, word.Substring(0, 1) descending 
4                    select word;
5 
6 foreach (var word in query)
7 {
8     Console.WriteLine(word);
9 }
下面經過演示使用 orderby descending 進行主要和次要排序:先升序按字符串長度(主)、再降序按字符串的第一個字母(次)

 

 

3、Set 操做

  LINQ 中的 Set 操做是指根據相同或不一樣集合中是否存在等效元素來生成結果集的查詢操做數據庫

 

標準查詢運算符操做方法 - Set
方法名 說明

C# 查詢表達式語法編程

Distinct數組

從集合移除重複值。數據結構

X

Exceptapp

返回差集,差集是指位於一個集合但不位於另外一個集合的元素。框架

X

Intersectide

返回交集,交集是指同時出如今兩個集合中的元素。函數

X

Unionpost

返回並集,並集是指位於兩個集合中任一集合的惟一的元素。

X

 

  圖解 Set 操做

  (1)Distinct: 返回的序列包含輸入序列的惟一元素。

  (2)Except: 返回的序列只包含位於第一個輸入序列但不位於第二個輸入序列的元素。  

  (3)Intersect: 返回的序列包含兩個輸入序列共有的元素。  

  (4)Union: 返回的序列包含兩個輸入序列的惟一的元素。 
顯示兩個序列的聯合的圖。

 

 4、過濾數據

      篩選指將結果集限制爲只包含某些知足指定條件的元素的操做。它又稱爲 選擇
     下圖演示了對字符序列進行篩選的結果。篩選操做的謂詞指定字符必須爲「A」。

 

標準查詢運算符操做方法 - 篩選
方法名 說明 C# 查詢表達式語法
OfType 根據值強制轉換爲指定類型的能力選擇值。 X
Where 選擇基於謂詞函數的值。 where
  
  示例:
 1 string[] words = { "the", "quick", "brown", "fox", "jumps" };
 2 
 3 var query = from word in words
 4                    where word.Length == 3
 5                    select word;
 6 
 7 foreach (var word in query)
 8 {
 9      Console.WriteLine(word);
10 }
使用 where 子句來從數組中篩選那些具備特定長度的字符串

 

5、量詞操做 

  限定符運算返回一個 Boolean 值,該值指示序列中是否有一些元素知足條件或是否全部元素都知足條件。

     下圖描述了兩個不一樣源序列上的兩個不一樣限定符運算。第一個運算詢問是否有一個或多個元素爲字符「A」,結果爲  true。第二個運算詢問是否全部元素都爲字符「A」,結果爲  true。  
 

標準查詢運算符操做方法 - 量詞

方法名

說明

C# 查詢表達式語法

All

肯定是否序列中的全部元素都知足條件。

X
Any

肯定序列中是否有元素知足條件。

X

Contains

肯定序列是否包含指定的元素。

X

 

6、投影操做

      投影是指將對象轉換爲一種新形式的操做,該形式一般只包含那些將隨後使用的屬性。經過使用投影,您能夠構建依據每一個對象生成的新類型。您能夠映射屬性,並對該屬性執行數學函數。還能夠在不更改原始對象的狀況下映射該對象。
 
標準查詢運算符操做方法 - 投影
方法名 說明 C# 查詢表達式語法
Select 映射基於轉換函數的值。 select
SelectMany 映射基於轉換函數的值序列,而後將它們展平爲一個序列。 使用多個 from 子句
  
  示例
1 var words = new[] { "the", "quick", "brown", "fox", "jumps" };
2 var query = from word in words
3                    select word.Substring(0,1);
4 
5 foreach (var word in query)
6 {
7     Console.WriteLine(word);
8 }
Select:下面的示例使用 select 子句來映射字符串列表中每一個字符串的第一個字母

 

 1 var phrases = new List<string>() { "an apple a day", "the quick brown fox" };
 2 
 3 var query = from phrase in phrases
 4                    from word in phrase.Split(' ')
 5                    select word;
 6 
 7 foreach (var word in query)
 8 {
 9    Console.WriteLine(word);
10 }
SelectMany:下面的示例使用多個 from 子句來映射字符串列表中每一個字符串中的每一個單詞

  

  Select() 和 SelectMany() 的工做都是依據源值生成一個或多個結果值。Select() 爲每一個源值生成一個結果值。所以,整體結果是一個與源集合具備相同元素數目的集合。與之相反,SelectMany() 將生成單一整體結果,其中包含來自每一個源值的串聯子集合。做爲參數傳遞到 SelectMany() 的轉換函數必須爲每一個源值返回一個可枚舉值序列。而後,SelectMany() 將串聯這些可枚舉序列以建立一個大的序列。

  下面兩個插圖演示了這兩個方法的操做之間的概念性區別。在每種狀況下,假定選擇器(轉換)函數從每一個源值中選擇一個由花卉數據組成的數組。

  下圖描述 Select() 如何返回一個與源集合具備相同元素數目的集合。

 

  下圖描述 SelectMany() 如何將中間數組序列串聯爲一個最終結果值,其中包含每一箇中間數組中的每一個值。

 

  示例

  下面的示例比較 Select() 和 SelectMany() 的行爲。代碼將經過從源集合的每一個花卉名稱列表中提取前兩項來建立一個「花束」。在此示例中,轉換函數 Select 使用的「單一值」自己就是一個值集合。這須要額外的 foreach 循環,以便枚舉每一個子序列中的每一個字符串。

 1         static void Main(string[] args)
 2         {
 3             var bouquets = new List<Bouquet>()
 4             {
 5                 new Bouquet {Flowers = new List<string> {"sunflower", "daisy", "daffodil", "larkspur"}},
 6                 new Bouquet {Flowers = new List<string> {"tulip", "rose", "orchid"}},
 7                 new Bouquet {Flowers = new List<string> {"gladiolis", "lily", "snapdragon", "aster", "protea"}},
 8                 new Bouquet {Flowers = new List<string> {"larkspur", "lilac", "iris", "dahlia"}}
 9             };
10 
11             IEnumerable<List<string>> query1 = bouquets.Select(bq => bq.Flowers);
12             IEnumerable<string> query2 = bouquets.SelectMany(bq => bq.Flowers);
13 
14             Console.WriteLine("query1 - Select():");
15             foreach (IEnumerable<string> collection in query1)
16             {
17                 foreach (var item in collection)
18                 {
19                     Console.WriteLine(item);
20                 }
21             }
22 
23             Console.WriteLine("\nquery2 - SelectMany():");
24             foreach (var item in query2)
25             {
26                 Console.WriteLine(item);
27             }
28 
29             Console.Read();
30         }
31 
32         class Bouquet
33         {
34             public List<string> Flowers { get; set; }
35         }        
View Code

 

7、劃分數據

  LINQ 中的分區指的是在不從新排列元素的狀況下,將輸入序列劃分爲兩部分,而後返回其中一個部分的操做。

  下圖顯示對一個字符序列執行三個不一樣的分區操做的結果。第一個操做返回序列中的前三個元素。第二個操做跳過前三個元素,返回剩餘的元素。第三個操做跳過序列中的前兩個元素,返回接下來的三個元素。  

 

分區序列的標準查詢運算符方法

運算符名稱

說明

C# 查詢表達式語法

Skip

跳過序列中的指定位置以前的元素。

X

SkipWhile

基於謂詞函數跳過元素,直到某元素再也不知足條件。

X

Take

提取序列中的指定位置以前的元素。

X

TakeWhile

基於謂詞函數提取元素,直到某元素再也不知足條件。 X

 

8、聯接操做

  將兩個數據源「聯接」就是將一個數據源中的對象與另外一個數據源中共享某個通用特性的對象關聯起來。

  當查詢所面向的數據源相互之間具備沒法直接領會的關係時,聯接就成爲一項重要的運算。在面向對象的編程中,這可能意味着在未建模對象之間進行關聯,例如對單向關係進行反向推理。下面是單向關係的一個示例:Customer 類有一個類型爲 City 的屬性,但 City 類沒有做爲 Customer 對象集合的屬性。若是你具備一個 City 對象列表,而且要查找每一個城市中的全部客戶,則可使用聯接運算完成此項查找。  

  LINQ 框架中提供的聯接方法包括 Join 和 GroupJoin。這些方法執行同等聯接,即根據兩個數據源的鍵是否相等來匹配這兩個數據源的聯接。(與此相較,Transact-SQL 支持除「等於」以外的聯接運算符,例如「小於」運算符。)用關係數據庫術語表達,就是說 Join 實現了內部聯接,這種聯接只返回那些在另外一個數據集中具備匹配項的對象。GroupJoin 方法在關係數據庫術語中沒有直接的等效項,但它實現了內部聯接和左外部聯接的超集。左外部聯接是這樣一種聯接:它返回第一個(左)數據源的每一個元素,即便該元素在另外一個數據源中沒有關聯元素。  

  下圖顯示了一個概念性視圖,其中包含兩個集合以及這兩個集合中的包含在內部聯接或左外部聯接中的元素。

 

標準查詢運算符操做方法 - 聯接

方法名

描述

C# 查詢表達式語法

Join

根據鍵選擇器函數聯接兩個序列並提取值對。

join … in … on … equals …

GroupJoin

根據鍵選擇器函數聯接兩個序列,並對每一個元素的結果匹配項進行分組。

join … in … on … equals … into …

 

9、分組數據

  分組指將數據放入組中以便每一個組中的元素共享公共特性的操做。
  下圖顯示了對字符序列進行分組的結果。每一個組的 是字符。  

 

標準查詢運算符方法 - 分組

方法名

說明

C# 查詢表達式語法

GroupBy

對共享公共特性的元素進行分組。  每一個組都由一個 IGrouping<TKey, TElement> 對象表示。  

group … by 

- 或 -

group … by … into …

ToLookup

根據鍵選擇器函數將元素插入到 Lookup<TKey, TElement>(一個一對多字典)中。

X

 

 1 var numbers = new List<int>() { 35, 44, 200, 84, 3987, 4, 199, 329, 446, 208 };
 2 
 3 IEnumerable<IGrouping<bool, int>> query = from number in numbers
 4                                                       group number by number % 2 == 0;
 5 
 6 foreach (var group in query)
 7 {
 8     Console.WriteLine($"{(group.Key ? "偶數" : "基數")}:");
 9     foreach (var i in group)
10     {
11         Console.WriteLine(i);
12     }
13 }    
使用 group by 子句根據列表中的整數是奇數仍是偶數進行分組

 

10、生成操做

  生成是指 建立新的值序列
 
標準查詢運算符方法 - 生成

方法名

說明

C# 查詢表達式語法

DefaultIfEmpty

將空集合替換爲具備默認值的單一實例集合。

X
Empty

返回空集合。

X
Range

生成包含數字序列的集合。

X

Repeat

生成包含一個重複值的集合。

X

 

11、等值操做

  若是兩個序列的對應元素相等且這兩個序列具備相同數量的元素,則視這兩個序列相等。
 
 
標準查詢運算符方法 - 等值
方法名 說明 C# 查詢表達式語法
SequenceEqual 經過成對地比較元素肯定兩個序列是否相等。 X

 

 12、元素操做

  元素操做從一個序列返回單個特定元素

 

標準查詢運算符操做方法 - 元素 

方法名

說明

C# 查詢表達式語法

ElementAt

返回集合中指定索引處的元素。

X

ElementAtOrDefault

返回集合中指定索引處的元素;若是索引超出範圍,則返回默認值。

X

First

返回集合中的第一個元素或知足條件的第一個元素。

X

FirstOrDefault

返回集合中的第一個元素或知足條件的第一個元素。  若是沒有這樣的元素,則返回默認值。  

X
Last

返回集合中的最後一個元素或知足條件的最後一個元素。

X

LastOrDefault

返回集合中的最後一個元素或知足條件的最後一個元素。  若是沒有這樣的元素,則返回默認值。  

X

Single

返回集合中的惟一元素或知足條件的惟一元素。

X

SingleOrDefault

返回集合中的惟一元素或知足條件的惟一元素。  若是沒有這樣的元素或集合不是正好包含一個元素,則返回默認值。  

X

 

十3、轉換數據類型

  轉換方法更改輸入對象的類型

  LINQ 查詢中的轉換運算可用於各類應用程序。下面是一些示例:

  (1)Enumerable.AsEnumerable<TSource> 方法可用於隱藏類型的標準查詢運算符的自定義實現。

  (2)Enumerable.OfType<TResult> 方法可用於啓用非參數化集合以進行 LINQ 查詢。

  (3)Enumerable.ToArray<TSource>Enumerable.ToDictionary<TSource, TKey>Enumerable.ToList<TSource>Enumerable.ToLookup<TSource, TKey> 方法可用於強制當即執行查詢,而非推遲到枚舉查詢時。

 

標準查詢運算符方法 - 轉換數據類型
方法名 說明 C# 查詢表達式語法
AsEnumerable 返回類型爲 IEnumerable<T> 的輸入。 X
AsQueryable 將(泛型)IEnumerable 轉換爲(泛型)IQueryable X
Cast 將集合的元素強制轉換爲指定類型。

使用顯式類型化的範圍變量。 例如:

from string str in words

OfType 根據值強制轉換爲指定類型的能力篩選值。 X
ToArray 將集合轉換爲數組。 此方法強制執行查詢。 X
ToDictionary 根據鍵選擇器函數將元素放入 Dictionary<TKey, TValue> 中。 此方法強制執行查詢。 X
ToList 將集合轉換爲 List<T>此方法強制執行查詢。 X
ToLookup 根據鍵選擇器函數將元素放入 Lookup<TKey, TElement>(一對多字典)中。 此方法強制執行查詢。 X

   

  示例:

 1         static void Main(string[] args)
 2         {
 3             var plants = new Plant[]
 4             {
 5                 new CarnivorousPlant {Name = "Venus Fly Trap", TrapType = "Snap Trap"},
 6                 new CarnivorousPlant {Name = "Pitcher Plant", TrapType = "Pitfall Trap"},
 7                 new CarnivorousPlant {Name = "Sundew", TrapType = "Flypaper Trap"},
 8                 new CarnivorousPlant {Name = "Waterwheel Plant", TrapType = "Snap Trap"}
 9             };
10 
11             var query = from CarnivorousPlant plant in plants
12                         where plant.TrapType == "Snap Trap"
13                         select plant;
14 
15             foreach (var carnivorousPlant in query)
16             {
17                 Console.WriteLine(carnivorousPlant.Name);
18             }
19 
20             Console.Read();
21         }
22 
23         class Plant
24         {
25             public string Name { get; set; }
26         }
27 
28         class CarnivorousPlant : Plant
29         {
30             public string TrapType { get; set; }
31         }    
使用顯式類型化的範圍變量將類型強制轉換爲子類型,而後才訪問僅在此子類型中提供的成員。

 

十4、串聯操做

  串聯是指將一個序列追加到另外一個序列的運算。

  下圖演示對兩個字符序列執行的串聯運算。

 

標準查詢運算符操做方法 - 串聯

方法名

說明

C# 查詢表達式語法

Concat

串聯兩個序列以組成一個序列。

X

 

十5、聚合操做

  聚合運算從值集合計算單個值。從一個月的日溫度值計算日平均溫度就是聚合運算的一個示例。  

  下圖顯示了對一個數字序列執行兩個不一樣聚合運算的結果。第一個運算對這些數字執行求和。第二個運算返回該序列中的最大值。  

 

 

標準查詢運算符操做方法 - 聚合

方法名

說明

C# 查詢表達式語法

Aggregate

對集合值執行自定義聚合運算。

X

Average

計算值集合的平均值。

X
Count

對集合中的元素進行計數,還能夠僅對知足某一謂詞函數的元素進行計數。

X

LongCount

對大型集合中的元素進行計數,還能夠僅對知足某一謂詞函數的元素進行計數。

X
Max

肯定集合中的最大值。

X
Min

肯定集合中的最小值。

X

Sum

計算集合中值的總和。

X

 

 傳送門

  入門:《走進 LINQ 的世界

  進階:《LINQ 標準查詢操做概述(強烈推薦)

  技巧:《Linq To Objects - 如何操做字符串》 和 《Linq To Objects - 如何操做文件目錄

  

 


【參考】https://msdn.microsoft.com/zh-cn/library/bb397896(v=vs.100).aspx

【來源】部分圖片摘自微軟官方文檔

相關文章
相關標籤/搜索