本筆記摘抄自:https://www.cnblogs.com/liqingwen/p/5801249.html,記錄一下學習程序以備后續查用,

“標準查詢運算子”是組成語言集成查詢 (LINQ) 模式的方法,大多數這些方法都在序列上運行,其中的序列是一個物件,其型別實作了IEnumerable<T>介面
或 IQueryable<T> 介面,標準查詢運算子提供了包括篩選、投影、聚合、排序等功能在內的查詢功能,各個標準查詢運算子在執行時間上有所不同,具體情況
取決于它們是回傳單一值還是值序列:
回傳單一值的方法(例如Average和Sum)會立即執行,回傳序列的方法會延遲查詢執行,并回傳一個可列舉的物件,
對于在記憶體中集合上運行的方法(即擴展IEnumerable<T>的方法),回傳的可列舉物件將捕獲傳遞到方法的引數,在列舉該物件時,將使用查詢運算子的
邏輯,并回傳查詢結果,與之相反,擴展IQueryable<T>的方法不會實作任何查詢行為,但會生成一個表示要執行的查詢的運算式樹,查詢處理由源
IQueryable<T>物件處理,
一、按標準執行方式分類
標準查詢運算子方法的LINQ to Objects實作采用兩種主要方式之一來執行:立即執行和延遲執行,采用延遲執行的查詢運算子可以進一步分為兩類:流式和
非流式,
1、執行方式
立即執行:立即執行意味著在代碼中宣告查詢的位置讀取資料源并執行運算,回傳單個不可列舉的結果的所有標準查詢運算子都立即執行,
延遲執行:延遲執行意味著不在代碼中宣告查詢的位置執行運算,僅當對查詢變數進行列舉操作時才執行運算,例如通過使用foreach陳述句,這意味著查詢的
執行結果取決于執行查詢而非定義查詢時的資料源內容,如果多次列舉查詢變數,則每次結果可能都不同,幾乎所有回傳型別為IEnumerable<T>或
IOrderedEnumerable<TElement>的標準查詢運算子都以延遲方式執行,
2、延遲執行
流式:運算子不需要在生成元素前讀取所有源資料,在執行時,流式運算子一邊讀取每個源元素,一邊對該源元素執行運算,并在可行時生成元素,流式運
算符將持續讀取源元素直到可以生成結果元素,這意味著可能要讀取多個源元素才能生成一個結果元素,
非流式:運算子必須讀取所有源資料才能生成結果元素,諸如排序和分組等運算屬于此類別,在執行時,非流式查詢運算子讀取所有源資料,將其放入資料
結構中,執行運算然后生成結果元素,
二、排列資料
排序操作按一個或多個特性對序列的元素進行排序,第一個排序條件對元素執行主要排序,通過指定第二個排序條件,可以對各個主要排序組中的元素進行
排序,
下圖演示對一個字符序列按字母排序操作的執行結果 :

| 方法名 | 說明 | C# 查詢運算式語法 |
| OrderBy | 按升序對值進行排序, | orderby |
| OrderByDescending | 按降序對值進行排序, | orderby … descending |
| ThenBy | 按升序執行次要排序, | orderby …, … |
| ThenByDescending | 按降序執行次要排序, | orderby …, … descending |
| Reverse | 顛倒集合中的元素的順序, | X |
下面代碼演示orderby升序排序:
class Program { static void Main(string[] args) { #region LINQ orderby升序排序 var words = new[] { "the", "quick", "brown", "fox", "jumps" }; var query = from word in words orderby word.Length select word; foreach (var word in query) { Console.WriteLine(word); } Console.Read(); #endregion } }View Code
運行結果如下:

下面代碼演示orderby降序排序:
class Program { static void Main(string[] args) { #region LINQ orderby降序排序 var words = new[] { "the", "quick", "brown", "fox", "jumps" }; var query = from word in words orderby word.Substring(0, 1) descending select word; foreach (var word in query) { Console.WriteLine(word); } Console.Read(); #endregion } }View Code
運行結果如下:

下面代碼演示orderby主要和次要排序(示例一):
class Program { static void Main(string[] args) { #region LINQ orderby主要和次要排序示例一 var words = new[] { "the", "quick", "brown", "fox", "jumps" }; var query = from word in words orderby word.Length, word.Substring(0, 1) select word; foreach (var word in query) { Console.WriteLine(word); } Console.Read(); #endregion } }View Code
運行結果如下:

下面代碼演示orderby主要和次要排序(示例二):
class Program { static void Main(string[] args) { #region LINQ orderby主要和次要排序示例二 var words = new[] { "the", "quick", "brown", "fox", "jumps" }; var query = from word in words orderby word.Length, word.Substring(0, 1) descending select word; foreach (var word in query) { Console.WriteLine(word); } Console.Read(); #endregion } }View Code
運行結果如下:

三、Set 操作
LINQ中的Set操作是指根據相同或不同集合中是否存在等效元素來生成結果集的查詢操作,
| 方法名 | 說明 |
C# 查詢運算式語法 |
|
Distinct |
從集合移除重復值, |
X |
|
Except |
回傳差集,差集是指位于一個集合但不位于另一個集合的元素, |
X |
|
Intersect |
回傳交集,交集是指同時出現在兩個集合中的元素, |
X |
|
Union |
回傳并集,并集是指位于兩個集合中任一集合的唯一的元素, |
X |
圖解Set操作
1、Distinct: 回傳的序列包含輸入序列的唯一元素,

2、Except: 回傳的序列只包含位于第一個輸入序列但不位于第二個輸入序列的元素,

3、Intersect: 回傳的序列包含兩個輸入序列共有的元素,

4、Union: 回傳的序列包含兩個輸入序列的唯一的元素,

四、過濾資料
篩選指將結果集限制為只包含某些滿足指定條件的元素的操作,它又稱為選擇,
下圖演示了對字符序列進行篩選的結果,篩選操作的謂詞指定字符必須為“A”,

| 方法名 | 說明 | C# 查詢運算式語法 |
| OfType | 根據值強制轉換為指定型別的能力選擇值, | X |
| Where | 選擇基于謂詞函式的值, | where |
下面代碼演示過濾資料:
class Program { static void Main(string[] args) { #region LINQ 過濾資料 string[] words = { "the", "quick", "brown", "fox", "jumps" }; var query = from word in words where word.Length == 3 select word; foreach (var word in query) { Console.WriteLine(word); } Console.Read(); #endregion } }View Code
運行結果如下:

五、量詞操作
限定符運算回傳一個Boolean值,該值指示序列中是否有一些元素滿足條件或是否所有元素都滿足條件,
下圖描述了兩個不同源序列上的兩個不同限定符運算,第一個運算詢問是否有一個或多個元素為字符“A”,結果為true,第二個運算詢問是否所有元素都為字符“A”,結果為true,

|
方法名 |
說明 |
C# 查詢運算式語法 |
| All |
確定是否序列中的所有元素都滿足條件, |
X |
| Any |
確定序列中是否有元素滿足條件, |
X |
|
Contains |
確定序列是否包含指定的元素, |
X |
六、投影操作
投影是指將物件轉換為一種新形式的操作,該形式通常只包含那些將隨后使用的屬性,通過使用投影,您可以構建依據每個物件生成的新型別,還可以映射
屬性,并對該屬性執行數學函式,另外還可以在不更改原始物件的情況下映射該物件,
| 方法名 | 說明 | C# 查詢運算式語法 |
| Select | 映射基于轉換函式的值, | select |
| SelectMany | 映射基于轉換函式的值序列,然后將它們展平為一個序列, | 使用多個 from 子句 |
下面代碼演示Select:
class Program { static void Main(string[] args) { #region LINQ Select var words = new[] { "the", "quick", "brown", "fox", "jumps" }; var query = from word in words select word.Substring(0, 1); foreach (var word in query) { Console.WriteLine(word); } Console.Read(); #endregion } }View Code
運行結果如下:

下面代碼演示SelectMany:
class Program { static void Main(string[] args) { #region LINQ SelectMany var phrases = new List<string>() { "an apple a day", "the quick brown fox" }; var query = from phrase in phrases from word in phrase.Split(' ') select word; foreach (var word in query) { Console.WriteLine(word); } Console.Read(); #endregion } }View Code
運行結果如下:

Select()和SelectMany()的作業都是依據源值生成一個或多個結果值,Select()為每個源值生成一個結果值,因此,總體結果是一個與源集合具有相同元素數
目的集合,與之相反,SelectMany()將生成單一總體結果,其中包含來自每個源值的串聯子集合,作為引數傳遞到SelectMany()的轉換函式必須為每個源值返
回一個可列舉值序列,然后,SelectMany() 將串聯這些可列舉序列以創建一個大的序列,
下面兩個插圖演示了這兩個方法的操作之間的概念性區別,在每種情況下,假定選擇器(轉換)函式從每個源值中選擇一個由花卉資料組成的陣列,
下圖描述 Select() 如何回傳一個與源集合具有相同元素數目的集合,

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

下面的示例比較Select()和SelectMany()的行為,代碼將通過從源集合的每個花卉名稱串列中提取前兩項來創建一個“花束”,在此示例中,轉換函式Select使用
的“單一值”本身就是一個值集合,這需要額外的foreach回圈,以便列舉每個子序列中的每個字串,
/// <summary> /// 花束類 /// </summary> class Bouquet { public List<string> Flowers { get; set; } } class Program { static void Main(string[] args) { #region LINQ Select和SelectMany比較 var bouquets = new List<Bouquet>() { new Bouquet {Flowers = new List<string> {"sunflower", "daisy", "daffodil", "larkspur"}}, new Bouquet {Flowers = new List<string> {"tulip", "rose", "orchid"}}, new Bouquet {Flowers = new List<string> {"gladiolis", "lily", "snapdragon", "aster", "protea"}}, new Bouquet {Flowers = new List<string> {"larkspur", "lilac", "iris", "dahlia"}} }; IEnumerable<List<string>> query1 = bouquets.Select(bq => bq.Flowers); IEnumerable<string> query2 = bouquets.SelectMany(bq => bq.Flowers); Console.WriteLine("query1->Select():"); foreach (IEnumerable<string> collection in query1) { foreach (var item in collection) { Console.WriteLine(item); } } Console.WriteLine("\nquery2->SelectMany():"); foreach (var item in query2) { Console.WriteLine(item); } Console.Read(); #endregion } }View Code
運行結果如下:

七、劃分資料
LINQ 中的磁區指的是在不重新排列元素的情況下,將輸入序列劃分為兩部分,然后回傳其中一個部分的操作,
下圖顯示對一個字符序列執行三個不同的磁區操作的結果,第一個操作回傳序列中的前三個元素;第二個操作跳過前三個元素,回傳剩余的元素;第三個操作
跳過序列中的前兩個元素,回傳接下來的三個元素,

|
運算子名稱 |
說明 |
C# 查詢運算式語法 |
|
Skip |
跳過序列中的指定位置之前的元素, |
X |
|
SkipWhile |
基于謂詞函式跳過元素,直到某元素不再滿足條件, |
X |
|
Take |
提取序列中的指定位置之前的元素, |
X |
|
TakeWhile |
基于謂詞函式提取元素,直到某元素不再滿足條件, | X |
八、聯接操作
將兩個資料源“聯接”就是將一個資料源中的物件與另一個資料源中共享某個通用特性的物件關聯起來,
當查詢所面向的資料源相互之間具有無法直接領會的關系時,聯接就成為一項重要的運算,在面向物件的編程中,這可能意味著在未建模物件之間進行關聯,
例如對單向關系進行反向推理,
LINQ 框架中提供的聯接方法包括Join和GroupJoin,這些方法執行同等聯接,即根據兩個資料源的鍵是否相等來匹配這兩個資料源的聯接,(與此相較,
Transact-SQL支持除“等于”之外的聯接運算子,例如“小于”運算子,)用關系資料庫術語表達,就是說Join實作了內部聯接,這種聯接只回傳那些在另一個資料集
中具有匹配項的物件,GroupJoin方法在關系資料庫術語中沒有直接的等效項,但它實作了內部聯接和左外部聯接的超集,左外部聯接是這樣一種聯接:它回傳第
一個(左)資料源的每個元素,即使該元素在另一個資料源中沒有關聯元素,
下圖顯示了一個概念性視圖,其中包含兩個集合以及這兩個集合中的包含在內部聯接或左外部聯接中的元素,

|
方法名 |
描述 |
C# 查詢運算式語法 |
| Join |
根據鍵選擇器函式聯接兩個序列并提取值對, |
join … in … on … equals … |
|
GroupJoin |
根據鍵選擇器函式聯接兩個序列,并對每個元素的結果匹配項進行分組, |
join … in … on … equals … into … |
九、分組資料
分組指將資料放入組中以便每個組中的元素共享公共特性的操作,
下圖顯示了對字符序列進行分組的結果,每個組的鍵是字符,

|
方法名 |
說明 |
C# 查詢運算式語法 |
|
GroupBy |
對共享公共特性的元素進行分組, 每個組都由一個 IGrouping<TKey, TElement> 物件表示, |
group … by - 或 - group … by … into … |
|
ToLookup |
根據鍵選擇器函式將元素插入到 Lookup<TKey, TElement>(一個一對多字典)中, |
X |
下面代碼演示分組資料:
class Program { static void Main(string[] args) { #region LINQ 分組資料 var numbers = new List<int>() { 35, 44, 200, 84, 3987, 4, 199, 329, 446, 208 }; IEnumerable<IGrouping<bool, int>> query = from number in numbers group number by number % 2 == 0; foreach (var group in query) { Console.WriteLine($"{(group.Key ? "偶數" : "基數")}:"); foreach (var item in group) { Console.WriteLine(item); } } Console.Read(); #endregion } }View Code
運行結果如下:

十、生成操作
生成是指創建新的值序列,
|
方法名 |
說明 |
C# 查詢運算式語法 |
|
DefaultIfEmpty |
將空集合替換為具有默認值的單一實體集合, |
X |
| Empty |
回傳空集合, |
X |
| Range |
生成包含數字序列的集合, |
X |
|
Repeat |
生成包含一個重復值的集合, |
X |
十一、等值操作
如果兩個序列的對應元素相等且這兩個序列具有相同數量的元素,則視這兩個序列相等,
| 方法名 | 說明 | C# 查詢運算式語法 |
| SequenceEqual | 通過成對地比較元素確定兩個序列是否相等, | X |
十二、元素操作
元素操作從一個序列回傳單個特定元素,
|
方法名 |
說明 |
C# 查詢運算式語法 |
|
ElementAt |
回傳集合中指定索引處的元素, |
X |
|
ElementAtOrDefault |
回傳集合中指定索引處的元素;如果索引超出范圍,則回傳默認值, |
X |
|
First |
回傳集合中的第一個元素或滿足條件的第一個元素, |
X |
|
FirstOrDefault |
回傳集合中的第一個元素或滿足條件的第一個元素,如果沒有這樣的元素,則回傳默認值, |
X |
| Last |
回傳集合中的最后一個元素或滿足條件的最后一個元素, |
X |
|
LastOrDefault |
回傳集合中的最后一個元素或滿足條件的最后一個元素,如果沒有這樣的元素,則回傳默認值, |
X |
|
Single |
回傳集合中的唯一元素或滿足條件的唯一元素, |
X |
|
SingleOrDefault |
回傳集合中的唯一元素或滿足條件的唯一元素,如果沒有這樣的元素或集合不是正好包含一個元素,則回傳默認值, |
X |
十三、轉換資料型別
轉換方法更改輸入物件的型別,
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 |
下面代碼演示轉換資料型別:
/// <summary> /// 植物類 /// </summary> class Plant { public string Name { get; set; } } /// <summary> /// 食肉植物類 /// </summary> class CarnivorousPlant : Plant { public string TrapType { get; set; } } class Program { static void Main(string[] args) { #region LINQ 轉換資料型別 var plants = new Plant[] { new CarnivorousPlant {Name = "Venus Fly Trap", TrapType = "Snap Trap"}, new CarnivorousPlant {Name = "Pitcher Plant", TrapType = "Pitfall Trap"}, new CarnivorousPlant {Name = "Sundew", TrapType = "Flypaper Trap"}, new CarnivorousPlant {Name = "Waterwheel Plant", TrapType = "Snap Trap"} }; var query = from CarnivorousPlant plant in plants where plant.TrapType == "Snap Trap" select plant; foreach (var carnivorousPlant in query) { Console.WriteLine(carnivorousPlant.Name); } Console.Read(); #endregion } }View Code
運行結果如下:

十四、串聯操作
串聯是指將一個序列追加到另一個序列的運算,
下圖演示對兩個字符序列執行的串聯運算,

|
方法名 |
說明 |
C# 查詢運算式語法 |
|
Concat |
串聯兩個序列以組成一個序列, |
X |
十五、聚合操作
聚合運算從值集合計算單個值,從一個月的日溫度值計算日平均溫度就是聚合運算的一個示例,
下圖顯示了對一個數字序列執行兩個不同聚合運算的結果,第一個運算對這些數字執行求和;第二個運算回傳該序列中的最大值,

|
方法名 |
說明 |
C# 查詢運算式語法 |
|
Aggregate |
對集合值執行自定義聚合運算, |
X |
|
Average |
計算值集合的平均值, |
X |
| Count |
對集合中的元素進行計數,還可以僅對滿足某一謂詞函式的元素進行計數, |
X |
|
LongCount |
對大型集合中的元素進行計數,還可以僅對滿足某一謂詞函式的元素進行計數, |
X |
| Max |
確定集合中的最大值, |
X |
| Min |
確定集合中的最小值, |
X |
|
Sum |
計算集合中值的總和, |
X |
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/87830.html
標籤:C#
下一篇:C# Charts繪制多條曲線
