天天看點

LINQ基礎介紹背景排序過濾選擇集合的并集、交叉和差異跳過和擷取方法分組連接配接集合Join方法All和Any方法結論

我将告訴您有關嵌入式LINQ語言的基礎知識。這将使您更輕松地使用C#語言。您不必使用類形式的全新工具集,而可以對現有類使用所有相同的熟悉的集合和數組。這意味着您可以充分利用LINQ查詢,而對現有代碼的修改很少或沒有修改。LINQ to Objects功能由IEnumerable接口、序列和标準查詢操作提供。

介紹

讓我們看一下LINQ是什麼。LINQ是語言內建查詢。資料源可以是一個對象(實作IEnuberable接口,即标準集合、數組)、XML文檔和DBSet資料集。但是,無論資料源如何,LINQ都采用相同的方法從該資料中擷取資料。另外,LINQ有很多變體:

  • LINQ to Objects:用于處理數組和集合
  • LINQ to Entities:在通過Entity Framework技術通路資料庫時使用
  • LINQ to SQL:MS SQL Server中的資料通路技術
  • LINQ to XML:在處理XML檔案時使用
  • LINQ to DataSet:在使用DataSet對象時使用
  • Parallel LINQ(PLINQ):用于執行并行查詢

在本文中,我首先要談談第一種LINQ語言。

背景

首先,為了了解它的含義,我将向您展示第一個執行個體:

string[] Contries = { "USA", "Canada", "United Kingdom", "Mexico", "China", "Uruguay" };
            var SelectedContr = new List<string>();
            foreach(string c in Contries)
            {
                if (c.StartsWith("U"))
                    SelectedContr.Add(c);
            }
            foreach (string s in SelectedContr)
                Console.WriteLine(s);
           

在其中,我們建立一些資料數組,然後周遊它,并在每次疊代時檢查比對項,如果是true,則寫入集合。如果我說這段代碼可以縮短幾次并且可以删除檢查條件的循環該怎麼辦?考慮使用LINQ語言編寫的代碼。要使用LINQ功能,請確定System.LINQ檔案中包含命名空間。

string[] Contries = { "USA", "Canada", "United Kingdom", "Mexico", "China", "Uruguay" };
            var SelectedContr = from C in Contries
                                where c.StartsWith("U")
                                select C;
            foreach (string s in SelectedContr)
                Console.WriteLine(s);
           

我們有相同的結果,但是可以通過更簡單的方式實作。該語言的定義是:

from variable in object_set
select variable;
           

是以,我們在示例中做了什麼,讓我們逐漸進行。Countries中的C表達式将C定義為數組的每個元素,是以,我們可以用它執行各種操作。MS Visual Studio自動識别出集合c由字元串對象組成,是以C變量将被視為string。這并不意味着LINQ不是強類型的。使用where時,對象将按特定條件過濾,但在發現的情況下,對象以字母“U”開頭。我們使用該select語句将所選值傳遞到LINQ表達式傳回的結果集中。

這樣的查詢的優點是它們在直覺上類似于SQL查詢,盡管它們有一些差別。另外,除了from…In…select之外,我們還有大量的擴充方法。這是整個清單:

  • Select:定義所選值的投影
  • Where:定義選擇過濾器
  • OrderBy:按升序排序項
  • OrderByDescending:以降序排序項
  • ThenBy:設定按升序排序項的其他條件
  • ThenByDescending:指定按降序排序項的其他條件
  • Join:在特定基礎上加入兩個集合
  • GroupBy:按鍵對項進行分組
  • ToLookup:按鍵對項進行分組,所有項目都添加到字典中
  • GroupJoin:按鍵執行集合加入和項分組
  • Reverse:颠倒順序
  • All:确定集合中的所有項目是否都滿足特定條件
  • Any:确定集合中的至少一個元素是否滿足特定條件
  • Contains:确定集合是否包含特定元素
  • Distinct:從集合中删除重複的項
  • Except:傳回兩個集合的差,即僅在一個集合中建立的那些項
  • Union:結合了兩個同類集合
  • Intersect:傳回兩個集合的交集,即兩個集合中出現的那些項
  • Count:計算集合中滿足特定條件的元素數
  • Sum:計算集合中數值的總和
  • Average:計算集合中數值的平均值
  • Min:找到最小值
  • Max:找到最大值
  • Take:選擇一定數量的項
  • Skip:跳過一定數量的項
  • TakeWhile:傳回條件序列,隻要條件是 true
  • SkipWhile:隻要滿足給定條件,就跳過序列中的元素,然後傳回其餘元素
  • Concat:結合了兩個集合
  • Zip:根據特定條件合并兩個集合
  • First:選擇集合中的第一項
  • FirstOrDefault:選擇集合中的第一項或傳回預設項
  • Single:選擇集合中的單個元素,如果集合中包含一個以上或少于一個元素,則會引發異常
  • SingleOrDefault:選擇集合中的第一項或傳回預設項
  • ElementAt:在特定索引處選擇序列的元素
  • ElementAtOrDefault:選擇特定索引處的集合元素,或者如果索引超出範圍,則傳回預設值
  • Last:選擇集合中的最後一項
  • LastOrDefault:選擇集合中的最後一項或傳回預設值

讓我們仔細看一下LINQ中的一些操作。

排序

用于按升序對資料集進行排序的linq語言使用oderby 運算符。讓我們看一下對數組排序的最簡單的例子。

int[] num = { 5, 7, 9, 3, 19, 25, 34 };
            var numord = from j in num
                           orderby j
                           select j;
            foreach (int c in numord)
                Console.WriteLine(c);
           

預設情況下,orderby運算符按升序排序。但是,使用關鍵字ascending (按升序排序)和descending (按降序排序),您可以顯式指定排序方向:如示例中一樣,我們按數字對數組進行排序,但是該語言允許您對更複雜的對象進行排序。考慮一個例子:

class People
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }
List<People> people = new List<People>
            {
                new People {Name = "Aron",Age= 19},
                new People {Name = "Bill",Age = 33},
                new People {Name = "Tom", Age = 7}
            };
            var sortedpeople = people.OrderBy(n => n.Name);
           

從示例中可以看到,我們使用了OrderBy擴充方法而不是orderby操作符。此外,您可以使用多個排序條件。考慮以下示例:

var result = from person in people
                         orderby person.Name, person.Age
                         select person;
           

在這裡,我們使用了兩個排序标準——name和age。

過濾選擇

Where 方法用于按條件從集合中選擇元素。讓我們考慮一個例子:

class People
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }
List<People> People = new List<People>
            {
                new People {Name = "Aron",Age= 5},
                new People {Name = "Pamela",Age = 5},
                new People {Name = "George",Age = 10},
                new People {Name = "Mark",Age = 30},
                new People {Name = "David",Age = 25},
                new People {Name = "Tim",Age = 25},
                new People {Name = "Jerry",Age = 25},
                new People {Name = "Tom", Age = 10}
            };
            IEnumerable<People> peoples = from p in People
                                          where p.Age == 25
                                          select p;
            foreach (var i in peoples)
                Console.WriteLine(i.Name);
           

在這裡,我們對年齡在25的人進行了分類。使用擴充方法的相同請求:

IEnumerable<People> peoples = People.Where(i => i.Age == 25) ;
           

集合的并集、交叉和差異

除了示例方法外,LINQ還提供了幾種方法,使您可以從兩個對象序列(差、并集和交集)生成一組唯一進制素。使用Except方法,可以獲得兩組的差。

string[] Female = { "Marta", "Dora", "Jane" , "Tim", "Tom", "Ben" };
            string[] Man = { "Tim", "Tom", "Ben" };

            var result = Female.Except(Man);
            foreach (string n in result)
                Console.WriteLine(n);
           

在這裡,Man數組中的所有元素都将從Female數組中删除。

為了獲得序列的交集,也就是說,這是兩組元素共有的序列, 使用了該Intersect方法。考慮一個例子:

string[] Female = { "Marta", "Dora", "Jane", "Tim" };
            string[] Man = { "Tim", "Tom", "Ben" };

            var result = Female.Intersect(Man);
            foreach (string n in result)
                Console.WriteLine(n);
           

在這種情況下,我們将得到結果“Tim”,因為在這兩個數組中隻有該元素是公共的。

該Union 方法用于合并兩個序列。讓我們考慮一個例子:

string[] Female = { "Marta", "Dora", "Jane", "Tim" };
            string[] Man = { "Tim", "Tom", "Ben" };
            var result = Female.Union(Man);
            foreach (string n in result)
                Console.WriteLine(n);
           

結果,我們将獲得一個新集合,其中包含來自第一和第二個數組的元素,并且沒有重複的元素。您可以使用該Distinct 方法删除項。

跳過和擷取方法

LINQ有兩種方法,Skip() 并Take()允許您建立分頁輸出。讓我們考慮一個例子:

int[] num = { 1,2,3,4,5,6,7,8,9 };
          var first = num.Take(5);
          foreach (int i in first)
              Console.WriteLine(i);

          var rest = num.Skip(5);
          foreach (int i in rest)
              Console.WriteLine(i);
           

結果,在第一種情況下,我們将采用前五個元素,在第二種情況下,我們将跳過前五個元素。但是,還有更多有趣的方法: TakeWhile()和SkipWhile()。考慮一個例子: 

int[] num = {1,1,2,3,4,5 };
            foreach (var c in num.TakeWhile(n=>n.Equals(1)))
                Console.WriteLine(c);
           

在我們的示例中,該TakeWhile()方法選擇從第一個元素開始直到滿足條件的元素集。該SkipWhile()方法以類似的方式工作。它從第一個元素開始循環周遊元素集,直到滿足特定條件為止。

分組

若要按特定參數對資料進行分組,請使用groupby 運算符或GroupBy()方法。讓我們考慮一個例子:

class People
    {
        public string Name { get; set; }

        public int Age { get; set; }
    }

List<People> People= new List<People>
            {
                new People {Name = "Aron",Age= 5},
                new People {Name = "Pamela",Age = 5},
                new People {Name = "George",Age = 10},
                new People {Name = "Mark",Age = 30},
                new People {Name = "David",Age = 25},
                new People {Name = "Tim",Age = 25},
                new People {Name = "Jerry",Age = 25},
                new People {Name = "Tom", Age = 10}
            };

            var PeopleGroups = from person in People
                              group person by person.Age;

            foreach (IGrouping<int, People> person in PeopleGroups)
            {
                Console.WriteLine(person.Key);
                foreach (var gr in person)
                    Console.WriteLine(gr.Name);
                Console.WriteLine();
            }
           

在此示例中,我們按年齡将人員分組。有一個特殊性:如果最後一個對LINQ表達式中的選擇執行操作的運算符是group, 則不應用該select語句。group 運算符接受由該分組執行的标準:group person by person.Age——在這種情況下,由Age屬性分組。

該group語句導緻選擇包含組。每個組代表一個IGrouping <string, People>對象:string參數訓示鍵的類型, People參數訓示分組的對象的類型。

每個組都有一個鍵,我們可以通過Key屬性獲得它: person.Key

可以使用其他疊代來擷取組中的所有元素。組項目的類型與傳遞給該group語句的對象的類型相同,在這種情況下,即為類型People的對象。可以使用GroupBy 擴充方法建構完全相同的查詢。考慮一個例子:

var PeopleGroups = People.GroupBy(p => p.Age);

            foreach (IGrouping<int, People> person in PeopleGroups)
            {
                Console.WriteLine(person.Key);
                foreach (var gr in person)
                    Console.WriteLine(gr.Name);
                Console.WriteLine();
            }
           

在這裡,我們應用了GroupBy 擴充方法,最終得到了相同的結果。

連接配接集合Join方法

如果需要将幾種不同類型的集合組合為一組,可以使用join 運算符。該join操作員或Join() 方法用于加入。通常,此操作應用于具有一個共同準則的兩個集合。讓我們考慮一個例子:

List<Country> countries = new List<Country>
            {
                new Country{Name ="USA",Population =330},
                new Country{Name ="Canada",Population = 37}
            };

            List<Capital> capitals = new List<Capital>
            {
                new Capital {Name= "Ottawa",CountryName="Canada"},
                new Capital {Name="Washington",CountryName="USA"}
            };

            var result = from c in countries
                         join cap in capitals on c.Name equals cap.CountryName
                         select new { Name = c.Name,CapitalName= cap.Name, 
                                      Population= c.Population };

            foreach (var item in result)
                Console.WriteLine($"{item.Name} , {item.CapitalName}, {item.Population}");
           

如果該c.Name屬性的值與該cap.CountryName屬性的值比對,則表達式join cap in capitals on c.Name equals cap.CountryName會将capitals清單中的cap與countries清單中的c相連。連接配接的結果将是一個匿名類型的對象,該對象将包含三個屬性。

該Join()方法可以完成相同的操作:

var result = countries.Join(capitals,
                p => p.Name,
                t => t.CountryName,
                (p, t) => new { Name = p.Name, CapitalName = t.Name, 
                                Population = p.Population });
           

該方法具有四個參數: Join()

  • 第二個清單,我們将其與目前清單連接配接
  • 目前清單中對象的屬性,通過該屬性建立連接配接
  • 連接配接的第二個清單中對象的屬性
  • 通過連接配接獲得的新對象

All和Any方法

如果我們需要确定集合是否滿足特定條件,那麼我們就可以使用Any,All,Contains方法。這些方法是boolean,并聲明true或false。

該All方法檢查是否所有項目都滿足條件。讓我們考慮一個例子:

List<People> People= new List<People>
            {
                new People {Name = "Aron",Age= 5},
                new People {Name = "Pamela",Age = 5},
                new People {Name = "George",Age = 10},
                new People {Name = "Mark",Age = 30},
                new People {Name = "David",Age = 25},
                new People {Name = "Tim",Age = 25},
                new People {Name = "Jerry",Age = 25},
                new People {Name = "Tom", Age = 10}
            };

bool result = People.All(p => p.Age > 25); // true
            if (result)
                Console.WriteLine("All people have age more then 25");
            else
                Console.WriteLine("We have people with age less 25");
            Console.ReadKey();
           

在此示例中,我們檢查了人們的年齡。當然,我們的年齡小于25,結果為false。

該Any 方法以類似的方式工作,僅允許您确定集合中的至少一個元素是否滿足特定條件,我們使用與上一個示例相同的類和對象集,但稍有改變。

bool result = People.Any(u => u.Age > 45);
if (result)
                Console.WriteLine("We have somebody more then 45 years");
            else
                Console.WriteLine("Nobody");
           

它傳回false,因為我們沒有年齡大于45的了。

結論

總之,使LINQ如此強大和易于使用的部分原因是它與C#語言的緊密內建。您不必使用類形式的全新工具集,而可以對現有類使用所有相同的熟悉的集合和數組。這意味着您可以充分利用LINQ查詢,而對現有代碼的修改很少或沒有修改。LINQ to Objects功能由IEnumerable<T>接口、序列和标準查詢操作提供。

https://www.codeproject.com/Tips/5291809/LINQ-Basics