C#每日一課(三十七)

LINQ查詢方法
LINQ中,數據源和查詢結果實際上都是IEnumerable或IQueryable類型的對象,所以可以像使用普通對象一樣使用調用方法,使用屬性等對數據源進行查詢和使用其結果數據。

  • IEnumerable接口
    這個泛型接口支持在指定數據集合上進行迭代操作。它定義了一些擴展的方法,用來對數據集合中的元素進行遍歷、過濾、排序、搜索、定位等相關操作。
    在 LINQ 中,數據源實際上是實現了接口IEnumerable的類,通過select子句返回的查詢結果也是一個實現了接口 IEnumerable的類。
    IEnumerable主要成員:
    Aggregate:對序列應用累加器函數,可以指定累加方法
    Sum:計算序列中所有元素的和,返回的值有int、long、double、decimal類型,並且可以指定元素到數值的映射方法
    Average:計算序列中所有元素的平均值,返回的值有int、long、double、decimal類型,並且可以指定元素到數值的映射方法
    Max:計算度序列中所有元素的最大值,返回的值有int、long、double、decimal類型,並且可以指定元素到數值的映射方法
    Min:計算度序列中所有元素的最小值,返回的值有int、long、double、decimal類型,並且可以指定元素到數值的映射方法
    All:檢查序列中是否所有元素都滿足條件,可以指定條件判斷方法。如果所有元素都滿足條件返回TRUE,否則返回FALSE
    Any:檢查序列中是否有任何一個元素滿足條件,可以指定條件判斷方法。如果有一個以上(含一個)元素滿足條件返回TRUE,否則返回FALSE
    Contains:檢查序列中是否包含特定元素,可以指定相等比較方法
    Count:返回序列中滿足指定條件的元素的數量,可以指定條件判斷方法
    LongCount:返回序列中滿足指定條件的元素的長數量,可以指定條件判斷方法
    Cast:把IEnumerable中的元素轉換爲指定的數據類型
    DefaultEmpty:返回序列中指定位置元素。如果序列爲空,則返回默認元素值
    ElementAt:返回序列中指定索引處的元素
    ElementAtOrDefault:返回序列中指定索引處的元素,如果索引超出範圍,則返回默認值
    First:返回序列中滿足指定條件的第一元素,可以指定條件判斷方法
    FirstOrDefault:返回序列中滿足指定條件的第一個元素。如果不存在則返回默認值,可以指定條件判斷方法
    Last:返回序列中滿足條件的最後一個元素,可以指定條件判斷方法
    LastOrDefault:返回序列中滿足條件的最後一個元素,如果不存在則返回默認值,可以指定條件判斷
    Single:返回序列中滿足指定條件的唯一元素,如果不止一個元素滿足條件則會產生異常,可以指定條件判斷方法
    SingleOrDefault:返回序列中滿足指定條件的唯一元素,如果不存在則返回默認值,如果不止一個元素滿足條件則會產生異常,可以指定條件判斷方法
    Reverse:返轉序列中元素的順序
    Distinct:返回序列中不重複的元素的集合,可以指定相等比較方法
    Concat:連接兩個序列,直接首尾相連。返回結果可能存在重複數據
    Except:獲取兩個元素集合的差集,可以指定相等比較方法
    Intersect:獲取兩個元素集合的交集,可以指定相等比較方法
    Union:獲取兩個元素集合的並集,可以指定相等比較方法
    SequenceEqual:比較兩個序列是否相等,可以指定相等比較方法
    Where:根據指定條件對集合是元素進行篩選,返回滿足條件的元素集合
    Skip:跳過序列中指定數量的元素,返回剩餘的元素
    SkipWhile:跳過序列中滿足指定條件的元素,然後返回剩餘的元素,可以指定條件判斷方法
    Take:從序列開頭返回指定數量的連續元素
    TakeWhile:返回從序列開始的滿足指定條件的連續元素,可以指定條件判斷方法
    ToArray:從IEnumerable創建一個數組
    ToList:從IEnumerable創建一個List

  • Lambda表達式
    查詢表達式—IEnumerable方法對應關係
    from子句指定元素類型—Cast(): 使用顯示類型化的範圍變量,比如:from int val in intArry
    group…by—GroupBy(): 對查詢結果進行分組
    group…by…into—GroupBy(): 對查詢結果進行分組
    join…in…on…equals…into—GroupJoin(): 左外聯接查詢
    join…in…on…equals—Join(): 內部聯接查詢
    orderby—OrderBy(): 從小到大排序
    orderby…descending—OrderByDescending(): 從大到小排序
    select—Select(): 指定映射元素
    select—SelectMany(): 從從個from子句進行查詢
    orderby…,…—ThenBy(): 多個排序元素,從小到大把序
    orderby…,…descending—ThenByDescending(): 多個排序元素,後一個元素從大到小排序
    Where—Where(): 條件過濾

  • 使用Where()方法進行篩選
    使用Visual Studio新建C#控制檯應用程序
    在生成的程序Main方法中添加如下代碼:

//數據源
int[] intArry = { 2, 4, 5, 7, 8, 9, 12, 11 };
//使用查詢方法,Lambda表達式
var query1 = intArry.Where(num=>num%2==0);
foreach (var val in query1)
{
    Console.Write("{0} ", val);
}
Console.WriteLine();
//使用查詢表達式
var query2 = from val in intArry where val % 2 == 0 select val;
foreach (var val in query2)
{
    Console.Write("{0} ", val);
}
Console.WriteLine();
Console.ReadKey();

當使用查詢方法時,Lambda表達式實際上是一個匿名函數,它包含表達式和語句,常用於創建委託或表達式目錄樹類型。
Lambda表達式都使用Lambda運算符"=>"
Lambda運算符的左邊是輸入參數(可能沒有),右邊是表達式或語句塊。
Lambda表達式返回右邊表達式的結果
基本語法格式如下:
(input params) => expression
params:是一個參數列表,如果輸入參數只有一個時可以不使用括號,否則一定要使用括號,並且多個參數使用逗號分隔。
一般來說Lambda表達式的參數都是可變類型的,由編譯器自動確定它的具體類型。有時候編譯器無法推斷其輸入類型時,則需要爲參數顯示指定類型。
當Lambda表達式沒有參數時,需要使用空的括來表示“()”表示沒有參數。

在Main方法中添加如下代碼:

/*使用Where()方法進行篩選案例*/
//num表示其元素值,index表示索引,從0開始
var query3 = intArry.Where(((num,index)=>num%(++index)==0));
foreach (var val in query3)
{
    Console.Write("{0} ", val);
}
Console.WriteLine();

編譯運行結果
運行結果

  • OrderBy()方法進行排序
    LINQ中,OrderBy()方法表示從小到大排序元素,也可以使用OrderByDescending()方法從大到小排序元素。
    在Main方法中添加如下測試代碼:
Console.Write("源數據:");
foreach (int item in intArry)
{
     Console.Write("{0} ", item);
}
Console.WriteLine();
//使用OrderBy()、OrderByDescending()進行排序
var query4 = intArry.OrderBy(val=>val);
foreach (var val in query4)
{
     Console.Write("{0} ", val);
}
Console.WriteLine();
var query5 = intArry.OrderByDescending(val => val);
foreach (var val in query5)
{
      Console.Write("{0} ", val);
}
Console.WriteLine();

編譯運行結果如下:
運行結果

如果沒有指定特定的數據比較器,編譯器使用默認的數據比較器。但當默認的數據比較器無法滿足時,就需要使用自定義的數據比較器
自定義數據比較器:
1.聲明一個自定義的比較器類,並繼承自IComparer接口
2.定義的比較器類中實例化Compare類
在調用OrderBy()、OrderByDescending()方法時,需要在最後傳入這個比較器類的實例化對象,以表明使用自定義的比較器

在程序中添加一個自定義的比較器類:

//自定義比較器
    class myCompare : IComparer<int>
    {
        //對比較方法的實現
        public int Compare(int x, int y)
        {
            int x1 = x * (x % 2);
            int y1 = y * (y % 2);
            if (x1 > y1)
                return 1;
            else if (x1 == y1)
                return 0;
            else
                return -1;
        }
    }

在Main方法中加上如下代碼進行測試:

Console.Write("源數據:");
            foreach (int item in intArry)
            {
                Console.Write("{0} ", item);
            }
            Console.WriteLine();
            Console.WriteLine("使用自定義排序方法後:");
            var query6 = intArry.OrderBy(val => val, new myCompare());
            foreach (var val in query6)
            {
                Console.Write("{0} ", val);
            }
            Console.WriteLine();

            var query7 = intArry.OrderByDescending(val => val, new myCompare());
            foreach (var val in query7)
            {
                Console.Write("{0} ", val);
            }
            Console.WriteLine();

編譯運行結果如下:
運行結果

  • Skip()、SkipWhile()跳過元素
    在一些查詢中如果明確是需要跳過某些元素,只取剩下的元素作爲查詢結果時,可以使用Skip()、SkipWhile()這兩個方法。
    Skip():簡單的跳過集合中指定數量的元素
    SkipWhile():跳過集合中滿足條件件的元素

在程序Main方法中加入如下代碼進行測試

//跳過查詢結查中的元素
            Console.Write("源數據:");
            foreach (int item in intArry)
            {
                Console.Write("{0} ", item);
            }
            Console.WriteLine();
            var query8 = intArry.SkipWhile((num,index) => num % (++index)==0);
            foreach (var val in query8)
            {
                Console.Write("{0} ", val);
            }
            Console.WriteLine();

編譯運行的結果如下:
運行結果

使用SkipWhile()的時候要注意了,它是按數據結果集順序去判斷是否滿足條件,如果滿足則剔除,至到遇到第一個不滿足的時候後面的就不在判斷並剔除了,所以上面的代碼中第一個元素2滿足,剔除,第二個元素4滿足,剔除,第三個元素5不滿足則不做剔除,並且後面的元素也不做判斷剔除了比如後面的元素8和12都輸出了。

  • Take()、TakeWhile()提取元素
    它與Skip()和SkipWhile()是相反的,表示當滿足時就提取出來,而不是剔除

在程序的Main方法中添加如下代碼進行測試:

//提取查詢結查中的指定元素
            Console.Write("源數據:");
            foreach (int item in intArry)
            {
                Console.Write("{0} ", item);
            }
            Console.WriteLine();
            var query9 = intArry.TakeWhile((num, index) => num % (++index) == 0);
            foreach (var val in query9)
            {
                Console.Write("{0} ", val);
            }
            Console.WriteLine();

編譯運行結果如下:
運行結果
TakeWhile()方法要注意的是,它從查詢結果是按順序進行提取元素,直到遇到第一個不滿足的時候後面的數據就全部不做提取了。

  • Max()等方法對元素進行數值計算
    對於實例中的數組可以直接使用
    Max()、Min()、Average()、Sum()對結查集中的數據進行求取大值、最小值以及求和等,比如:
    var intMax = intArry.Max();//求intArry中最大值
    var intMin = intArry.Min();//求intArry中最小值
    var intAverage = intArry.Average();//求intArry中平均值
    var intSum = intArry.Sum();//求intArry中的和

在實際的應用中也可能需要對非數值類型的數據進行求和、求平均、最大、最小值等操作,這個時候可在在函數參數中加入Lambda表達式來處理。

在程序Main方法中添加如下測試代碼:

 string[] strArry = { "謝聲","xiaoxie","advent"};
            int strMax = strArry.Max(val=>val.Length);
            int strMin = strArry.Min(val => val.Length);
            double strAvg = strArry.Average(val => val.Length);
            Console.Write("源數據:");
            foreach (var item in strArry)
            {
                Console.Write("{0} ", item);
            }
            Console.WriteLine();
            Console.Write("字符中長度最長:{0};最短{1};平均長度:{2}",strMax,strMin,strAvg);
            Console.WriteLine();

編譯運行結果如下:
運行結果

  • Distinct()方法進行去重
    在一些應用中,一個數據集合包含多條記錄,並且這些記錄存在重複的情況,對於重複出現的記錄只保留一條記錄。
    可以使用Distinct()方法進行去重處理,去重時編譯器要據默認的元素相等性判斷是否是同一元素進行去重操作,如果需要提供自定義的相等判斷需要自定義一個相等比較器來進行元素的重複性判斷。

在程序Main方法中添加如下測試代碼:

//Distinct()進行去重處理
            string[] strArry1 = { "advent1","xiaoxie","advent","advent1","謝聲"};
            var query10 = strArry1.Distinct();
            Console.Write("源數據:");
            foreach (var item in strArry1)
            {
                Console.Write("{0} ", item);
            }
            Console.WriteLine();
            Console.Write("元素去重後:");
            foreach (string str in query10)
            {
                Console.Write("{0} ", str);
            }

            Console.WriteLine();

            //Distinct()進行去重處理,使用了自定義的相等比較器
            myEquals<string> me = new myEquals<string>();
            var query11 = strArry1.Distinct(me);
            Console.Write("源數據:");
            foreach (var item in strArry1)
            {
                Console.Write("{0} ", item);
            }
            Console.WriteLine();
            Console.Write("元素去重後:");
            foreach (string str in query11)
            {
                Console.Write("{0} ", str);
            }

            Console.WriteLine();

編譯運行結果如下:
運行結果

  • Concat()方法連接兩個集合
    注意:連接的數據集合並必須是相同的數據類型,否則是不可以進行連接操作的。
    在程序Main方法中加處如下測試代碼:
//使用Concat()進行連接
            string[] str1 = { "C#", "Hello" };
            string[] str2 = { "OK!" };
            var query12 = str1.Concat(str2);
            foreach (string str in query12)
            {
                Console.Write("{0} ", str);
            }
            Console.WriteLine();
            var query13 = str2.Concat(str1);
            foreach (string str in query13)
            {
                Console.Write("{0} ", str);
            }
            Console.WriteLine();

編譯運行結果如下:
運行結果

  • Union()方法進行集合操作
    Union():並集
    Intersect():交集
    Except():差集
    這些主就去也是兩個重載的版本的,一個是使用默認的相等方式對元素比較來行成查詢結果集合,另一個是自定義一個相等比較器參數。

在程序Main方法中添加如下測試代碼如下:

//Union()等方法進行集合操作
            string[] str3 = {"advent1","謝聲","C#" };
            string[] str4 = { "謝聲", "小謝", "xiesheng", "Hello" };

            //Union()操作
            var query14 = str3.Union(str4);
            foreach (string str in query14)
            {
                Console.Write("{0} ", str);
            }
            Console.WriteLine();
            var query15 = str3.Union(str4,me);
            foreach (string str in query15)
            {
                Console.Write("{0} ", str);
            }
            Console.WriteLine();
            
            //Intersect()操作
            var query16 = str3.Intersect(str4);
            foreach (string str in query16)
            {
                Console.Write("{0} ", str);
            }
            Console.WriteLine();
            var query17 = str3.Intersect(str4, me);
            foreach (string str in query17)
            {
                Console.Write("{0} ", str);
            }
            Console.WriteLine();

            //Except()操作
            var query18 = str3.Except(str4);
            foreach (string str in query18)
            {
                Console.Write("{0} ", str);
            }
            Console.WriteLine();
            var query19 = str3.Except(str4, me);
            foreach (string str in query19)
            {
                Console.Write("{0} ", str);
            }
            Console.WriteLine();

編譯運行結果哪下:
運行結果

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章