天天看點

Linq To Object标準操作符最強總結

Where OfType<TResult>:

說明:篩選操作符定義了傳回元素的條件。Where查詢操作符中,可以使用謂詞。例如Lambda表達式定義的謂詞,來傳回布爾值。OfType<TResult>根據類型篩選元素,隻傳回TResult類型的元素。

Select和SelectMany:

投射操作符用于把對象轉為另一個類型的新的對象。Select和SelectMany定義了根據選擇器函數選擇結果值得投射。

OrderBy、ThenBy、OrderByDescending、ThenByDescending、Reverse:

排序操作符改變傳回的元素的順序。OrderBy按升序排序,OrderByDescending按降序排序。如果第一次排序的結果很類似,就可以使用ThenBy和ThenByDescending操作符進行第二次排序。Reverse反轉集合中元素的順序

Join、GroupJoin:

連接配接運算符用于合并不直接相關的集合。使用Join操作符,可以根據鍵選擇器函連接配接兩個集合,這類似于SQL中的Join。GroupJoin操作符連接配接兩個集合,組合其結果

GroupBy、ToLooKup:

組合運算符把資料放在組中。GroupBy操作符組合有公共鍵的元素。ToLoopup通過建立一個一對多的字典、來組合元素。

Any、All、Contains:

如果元素序列滿足指定的條件,量詞操作符就傳回布爾值。Any、All和Contains都是限定符操作符。Any确定集合中是否滿足謂詞函數的元素;All确定集合中的所有元素是否都滿足謂詞函數;Contains檢查某個元素是否存在集合中。這些操作符都傳回一個布爾值。

Take、Skip、TakeWhile、SkipWhile:

分區操作符傳回集合的一個子集。Take、Skip、TakeWhile和SkipWhile都是分區操作符。使用Take必須指定要從集合中提取的元素個數;Skip跳過指定的元素個數,提取元素;TakeWhile提取條件為真的元素。

Distinct、Union、Intersect、Except、Zip:

Set操作符傳回一個集合。Distinct從集合中删除重複的元素。除了Distinct之外,其他Set操作符都需要兩個集合。Union(并集)傳回出現在其中一個集合的唯一進制素。Intersect(交集)傳回兩個集合都有的元素。Except(差集)傳回隻出現一個集合中的元素。Zip是.Net新增的。它把兩個集合合并為一個。

First、FirstOrDefault、Last、LastOrDefault、ElementAt、ElementAtOrDefault、Single、SingleOrDefault:

這些元素操作符僅傳回一個元素。First傳回第一個滿足的元素。FirstOrDefault類似于First,但如果沒有找到滿足條件的元素,就傳回類型的預設值。Last傳回最後一個滿足條件的元素。ElementAt指定了要傳回的元素的位置。Single隻傳回一個滿足條件的元素。如果多個元素都滿足條件,就抛出一個異常。

Count、Sum、Min、Max、Average、Aggregate:

聚合操作符計算集合的一個值。利用這些聚合操作符,可以計算所有值得總和、所有元素的個數、值最大和最小的元素,以及平均值等。

ToArray、ToEnumerable、ToList、ToDictionary、Cast<TResult>:

這些轉換操作符将集合轉換為數組:IEnumerable、IList、IDictionary等。

Empty、Range、Repeat:

這些生成操作符傳回一個新集合。使用Empty時集合是空的;Range傳回一系列數字;Repeat傳回一個始終重複一個值的集合。

Enumerable類的Concat方法用來連接配接連個序列,并傳回由兩個數組中所有元素組成的新序列。

文法格式:

public static IEnumerable<TSource> Concat<TSource>(this IEnumerable<TSource> first ,IEnumerable<TSource> second)

first:要連接配接的第一個序列 second:要與第一序列連接配接的序列。

傳回值:一個IEnumerable<T>,包含連個輸入序列的元素。

Let字句:

在查詢表達式,存儲表達式的結果有時很有用,這樣可以在随後的字句中使用。

可以使用Let關鍵字完成這一工作,該關鍵字可以建立一個新的範圍變量,并且用你提供的表達式的結果初始化改變量。一旦用值初始化了該範圍變量,它就不能用于存儲其他值。但如果該範圍變量存儲的是可查詢的類型,則可以對其進行查詢。

應用舉例:

 資料部分:

 [Serializable]

   public class Team

   {

       public Team(string name, params int[] years)

       {

           this.Name = name;

           this.Years = years;

       }

       public string Name { get; private set; }

       public int[] Years { get; private set; }

   }

}

  [Serializable]

   public class Racer : IComparable<Racer>, IFormattable

       public Racer(string firstName = null, string lastName = null, string country = null, int starts = 0, int wins = 0, IEnumerable<int> years = null, IEnumerable<string> cars = null)

           this.FirstName = firstName;

           this.LastName = lastName;

           this.Country = country;

           this.Starts = starts;

           this.Wins = wins;

           var yearsList = new List<int>();

           foreach (var year in years)

           {

               yearsList.Add(year);

           }

           this.Years = yearsList.ToArray();

           var carList = new List<string>();

           foreach (var car in cars)

               carList.Add(car);

           this.Cars = carList.ToArray();

       public string FirstName { get; set; }

       public string LastName { get; set; }

       public string Country { get; set; }

       public int Wins { get; set; }

       public int Starts { get; set; }

       public string[] Cars { get; private set; }

       public override string ToString()

           return String.Format("{0} {1}", FirstName, LastName);

       public int CompareTo(Racer other)

           if (other == null) throw new ArgumentNullException("other");

           return this.LastName.CompareTo(other.LastName);

       public string ToString(string format)

           return ToString(format, null);

       public string ToString(string format,

             IFormatProvider formatProvider)

           switch (format)

               case null:

               case "N":

                   return ToString();

               case "F":

                   return FirstName;

               case "L":

                   return LastName;

               case "C":

                   return Country;

               case "S":

                   return Starts.ToString();

               case "W":

                   return Wins.ToString();

               case "A":

                   return String.Format("{0} {1}, {2}; starts: {3}, wins: {4}",

                         FirstName, LastName, Country, Starts, Wins);

               default:

                   throw new FormatException(String.Format("Format {0} not supported", format));

public static class Formula1

       private static List<Racer> racers;

       public static IList<Racer> GetChampions()

           if (racers == null)

               racers = new List<Racer>(40);

               racers.Add(new Racer("Nino", "Farina", "Italy", 33, 5, new int[] { 1950 }, new string[] { "Alfa Romeo" }));

               racers.Add(new Racer("Alberto", "Ascari", "Italy", 32, 10, new int[] { 1952, 1953 }, new string[] { "Ferrari" }));

               racers.Add(new Racer("Juan Manuel", "Fangio", "Argentina", 51, 24, new int[] { 1951, 1954, 1955, 1956, 1957 }, new string[] { "Alfa Romeo", "Maserati", "Mercedes", "Ferrari" }));

               racers.Add(new Racer("Mike", "Hawthorn", "UK", 45, 3, new int[] { 1958 }, new string[] { "Ferrari" }));

               racers.Add(new Racer("Phil", "Hill", "USA", 48, 3, new int[] { 1961 }, new string[] { "Ferrari" }));

               racers.Add(new Racer("John", "Surtees", "UK", 111, 6, new int[] { 1964 }, new string[] { "Ferrari" }));

               racers.Add(new Racer("Jim", "Clark", "UK", 72, 25, new int[] { 1963, 1965 }, new string[] { "Lotus" }));

               racers.Add(new Racer("Jack", "Brabham", "Australia", 125, 14, new int[] { 1959, 1960, 1966 }, new string[] { "Cooper", "Brabham" }));

               racers.Add(new Racer("Denny", "Hulme", "New Zealand", 112, 8, new int[] { 1967 }, new string[] { "Brabham" }));

               racers.Add(new Racer("Graham", "Hill", "UK", 176, 14, new int[] { 1962, 1968 }, new string[] { "BRM", "Lotus" }));

               racers.Add(new Racer("Jochen", "Rindt", "Austria", 60, 6, new int[] { 1970 }, new string[] { "Lotus" }));

               racers.Add(new Racer("Jackie", "Stewart", "UK", 99, 27, new int[] { 1969, 1971, 1973 }, new string[] { "Matra", "Tyrrell" }));

               racers.Add(new Racer("Emerson", "Fittipaldi", "Brazil", 143, 14, new int[] { 1972, 1974 }, new string[] { "Lotus", "McLaren" }));

               racers.Add(new Racer("James", "Hunt", "UK", 91, 10, new int[] { 1976 }, new string[] { "McLaren" }));

               racers.Add(new Racer("Mario", "Andretti", "USA", 128, 12, new int[] { 1978 }, new string[] { "Lotus" }));

               racers.Add(new Racer("Jody", "Scheckter", "South Africa", 112, 10, new int[] { 1979 }, new string[] { "Ferrari" }));

               racers.Add(new Racer("Alan", "Jones", "Australia", 115, 12, new int[] { 1980 }, new string[] { "Williams" }));

               racers.Add(new Racer("Keke", "Rosberg", "Finland", 114, 5, new int[] { 1982 }, new string[] { "Williams" }));

               racers.Add(new Racer("Niki", "Lauda", "Austria", 173, 25, new int[] { 1975, 1977, 1984 }, new string[] { "Ferrari", "McLaren" }));

               racers.Add(new Racer("Nelson", "Piquet", "Brazil", 204, 23, new int[] { 1981, 1983, 1987 }, new string[] { "Brabham", "Williams" }));

               racers.Add(new Racer("Ayrton", "Senna", "Brazil", 161, 41, new int[] { 1988, 1990, 1991 }, new string[] { "McLaren" }));

               racers.Add(new Racer("Nigel", "Mansell", "UK", 187, 31, new int[] { 1992 }, new string[] { "Williams" }));

               racers.Add(new Racer("Alain", "Prost", "France", 197, 51, new int[] { 1985, 1986, 1989, 1993 }, new string[] { "McLaren", "Williams" }));

               racers.Add(new Racer("Damon", "Hill", "UK", 114, 22, new int[] { 1996 }, new string[] { "Williams" }));

               racers.Add(new Racer("Jacques", "Villeneuve", "Canada", 165, 11, new int[] { 1997 }, new string[] { "Williams" }));

               racers.Add(new Racer("Mika", "Hakkinen", "Finland", 160, 20, new int[] { 1998, 1999 }, new string[] { "McLaren" }));

               racers.Add(new Racer("Michael", "Schumacher", "Germany", 250, 91, new int[] { 1994, 1995, 2000, 2001, 2002, 2003, 2004 }, new string[] { "Benetton", "Ferrari" }));

               racers.Add(new Racer("Fernando", "Alonso", "Spain", 132, 21, new int[] { 2005, 2006 }, new string[] { "Renault" }));

               racers.Add(new Racer("Kimi", "Räikkönen", "Finland", 148, 17, new int[] { 2007 }, new string[] { "Ferrari" }));

               racers.Add(new Racer("Lewis", "Hamilton", "UK", 44, 9, new int[] { 2008 }, new string[] { "McLaren" }));

           return racers;

  private static List<Team> teams;

       public static IList<Team> GetContructorChampions()

           if (teams == null)

               teams = new List<Team>()

               {

                   new Team("Vanwall", 1958),

                   new Team("Cooper", 1959, 1960),

                   new Team("Ferrari", 1961, 1964, 1975, 1976, 1977, 1979, 1982, 1983, 1999, 2000, 2001, 2002, 2003, 2004, 2007, 2008),

                   new Team("BRM", 1962),

                   new Team("Lotus", 1963, 1965, 1968, 1970, 1972, 1973, 1978),

                   new Team("Brabham", 1966, 1967),

                   new Team("Matra", 1969),

                   new Team("Tyrrell", 1971),

                   new Team("McLaren", 1974, 1984, 1985, 1988, 1989, 1990, 1991, 1998),

                   new Team("Williams", 1980, 1981, 1986, 1987, 1992, 1993, 1994, 1996, 1997),

                   new Team("Benetton", 1995),

                   new Team("Renault", 2005, 2006 )

               };

           return teams;

篩選:

使用Where字句,可以合并多個表達式。例如,找出赢得至少15場的巴西和奧地利賽手

使用Linq語句:

 var racers = from r in Formula1.GetChampions() where r.Wins > 15 && (r.Country == "Brazil" || r.Country == "Austria") select r;

foreach (var r in racers)

{

     Console.WriteLine("{0:A}", r);

    }

結果: Niki Lauda, Austria; starts: 173, wins: 25

Nelson Piquet, Brazil; starts: 204, wins: 23

Ayrton Senna, Brazil; starts: 161, wins: 41

使用擴充方法

第一種寫法:  var racers = Formula1.GetChampions().Where(r => r.Wins > 15 && (r.Country == "Brazil" || r.Country == "Austria")).Select(r=>r);

第二種寫法:  var racers = Formula1.GetChampions().Where(r => r.Wins > 15 && (r.Country == "Brazil" || r.Country == "Austria"));

    foreach (var r in racers)

      {

        Console.WriteLine("{0:A}", r);

          }

用索引篩選:下面由Where擴充方法調用,他使用索引傳回姓氏以A開頭,索引為偶數的賽手。

 var racers =Formula1.GetChampions().Where((r, index) => r.LastName.StartsWith("A") && index % 2 != 0);

    {

         }

結果:Alberto Ascari, Italy; starts: 32, wins: 10

Fernando Alonso, Spain; starts: 132, wins: 21

類型篩選:

使用OfType()擴充方法,把string類傳給泛型參數,就從集合中僅傳回字元串:

object[] data = { "one", 2, 3, "four", "five", 6 };

           var query = data.OfType<string>();

結果:

one

four

five

           foreach (var s in query)

               Console.WriteLine(s);

               }

符合的from字句

Racer類定義了屬性Cars,其中Cars是一個字元串數組。要篩選駕駛法拉利的所有冠軍。

第一個from字句通路從Formula1.GetChampions()方法傳回的Racer對象,第二個from字句通路Racer類的Cars屬性,以傳回所有string類型的賽車。接着在Where字句中使用這些賽車篩選駕駛法拉利的所有冠軍。

Linq語句寫法:

  var ferrariDrivers = from r in Formula1.GetChampions()

                                from c in r.Cars

                                where c == "Ferrari"

                                orderby r.LastName

                                select r.FirstName + " " + r.LastName;

擴充方法寫法:

var ferrariDrivers = Formula1.GetChampions().SelectMany(r => r.Cars, (r, c) => new { Racer = r, Car = c }).Where(r => r.Car == "Ferrari").OrderBy(r => r.Racer.LastName).Select(r => r.Racer.FirstName + " " + r.Racer.LastName);

周遊取出來的結果:

           foreach (var racer in ferrariDrivers)

               Console.WriteLine(racer);

結果:Alberto Ascari

Juan Manuel Fangio

Mike Hawthorn

Phil Hill

Niki Lauda

Kimi R?ikk?nen

Jody Scheckter

Michael Schumacher

John Surtees

符合的from字句和LINQ查詢轉換為SelectMany()擴充方法。SelectMany()方法可用于疊代序列的序列。示例中的SelectMany() 方法的重載版本如下:

   public static IEnumerable<TResult> SelectMany<TSource, TCollection, TResult>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TCollection>> collectionSelector, Func<TSource, TCollection, TResult> resultSelector);

第一個參數是隐式參數,它從GetChampions()方法中接收Racer對象序列。第二個參數是CollectionSelector委托,其中定義了内部序列。在Lambda表達式r=>r.Cars

中,應傳回賽車集合。第三個參數是一個委托,現在每個賽車調用該委托,它有Racer和Car屬性。這個SelectMany()方法的結果是攤平了賽手和賽車的層次結構,為每輛賽車傳回匿名類型的一個新對象集合。

          把SelectMany()泛型方法解析為這裡的使用類型;資料源是Racer類型,所篩選的集合是一個string數組,當傳回的是匿名類型的名稱是未知的,這裡顯示為TResult;

       public static IEnumerable<TResult> SelectMany<TSource, TCollection, TResult>(this IEnumerable<Racer> source,

Func<Racer, IEnumerable<string>> collectionSelector,

Func<Racer, string, TResult> resultSelector);

排序:

Linq寫法:

var query = from r in Formula1.GetChampions()

                       where r.Country == "Brazil"

                       orderby r.Wins descending

                       select r;

擴充方法:

          第一種:query= Formula1.GetChampions().Where(r => r.Country == "Brazil").OrderByDescending(r => r.Wins).Select(r=>r);

第二種:var query= Formula1.GetChampions().Where(r => r.Country == "Brazil").OrderByDescending(r => r.Wins);

周遊取出來的結果:foreach (var r in query)

                 {

                  Console.WriteLine("{0:A}", r);

                     }

結果:Ayrton Senna, Brazil; starts: 161, wins: 41

          elson Piquet, Brazil; starts: 204, wins: 23

          merson Fittipaldi, Brazil; starts: 143, wins: 14

OrderBy和OrderByDescending()方法傳回IOrderEnumerable<TSource>。這個接口派生自IEnumerable<TSource>(),這個方法用于進一步給序列排序。如果根據關鍵字選擇器來排序,其中兩項相同,就可以使用ThenBy()和ThenByDescending()方法繼續排序。這兩個方法需要IOrderEnumerable<TSource>接口才能工作,但也傳回這個接口。是以可以添加任意多個ThenBy()和ThenByDescending()方法,對集合排序。

  var  racers=(from r in Formula1.GetChampions() orderby r.Country,r.LastName,r.FirstName select r).Take(10);//Take(10)擴充方法用于提取前10個結果。

使用擴充方法:

  var racers= Formula1.GetChampions().OrderBy(r=>r.Country).ThenBy(r.LastName).ThenBy(r=>r.FirstName).Take(10);

分組:

Linq的寫法:

使用Group字句按照國家分組,并列出一個國家的冠軍數 Group r by r.Country into g 根據Country屬性組合所有賽手,并的那個一個新的辨別符 g,它以後用于通路分組的結果資訊。Group 字句的結果根據應用分組結果上的擴充方法Count()來排序,如果冠軍數相同,就根據關鍵字來排序,該關鍵字就是國家,因為這是分組所使用的關鍵字。Where字句根據至少有兩項的分組來篩選結果,Select字句建立一個帶Country和count屬性的匿名類型。

var countries = from r in Formula1.GetChampions()

                           group r by r.Country into g

                           orderby g.Count() descending, g.Key

                           where g.Count() >= 2

                           select new

                           {

                               Country = g.Key,

                               Count = g.Count()

                           };          

使用擴充方法:要用擴充方法執行相同的操作應把GroupBy字句解析為GroupBy()方法。在GroupBy()方法的聲明中,注意它傳回實作了IGrouping接口的對象。IGrouping接口定義了Key屬性,是以在定義了對這個方法的調用後,可以通路分組的關鍵字。

       public static IEnumerable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector);

把字句group r by r.Country into g 解析為GroupBy(r=>r.Country),傳回分組序列。分組序列首先用OrderByDescending()方法排序,再用ThenBy()方法排序。接着調用Where()和Select()方法。

var countries = Formula1.GetChampions().GroupBy(r => r.Country).OrderByDescending(g => g.Count()).ThenBy(g => g.Key).Where(g => g.Count() >= 2).Select(g => new

               Country = g.Key,

               Count= g.Count()

           });

周遊取出來的結果:foreach (var item in countries)

            {

               Console.WriteLine("{0, -10} {1}", item.Country, item.Count);

                }

結果:UK         9

   Brazil       3

          Finland      3

          Australia     2

          Austria       2

          Italy         2

          USA         2

對嵌套的對象分組:

如果分組的對象應包含嵌套的序列,就可以改變Select字句建立的匿名類型。在下面的例子中,所傳回的國家不僅包含國家名和賽手數量這兩個屬性,還包含賽手名序列。這個序列用一個賦予Racers屬性的from/in内部字句指定,内部的from字句使用分組辨別符g獲得該分組中的所有賽手,用姓氏對他們排序,在根據姓名建立一個新的字元串。

                               Count = g.Count(),

                               Racers = from r1 in g

                                        orderby r1.LastName

                                        select r1.FirstName + " " + r1.LastName

                           };

擴充方法的寫法:

  var countries = Formula1.GetChampions().GroupBy(r => r.Country).OrderByDescending(r => r.Count()).ThenBy(r => r.Key).Where(r => r.Count() >= 2).Select(r =>

                      new

                      {

                          Country = r.Key,

                          Count = r.Count(),

                          Racers = r.OrderBy(g => g.LastName).Select(g => g.FirstName + " " + g.LastName)

                      });

周遊取出的結果:

foreach (var item in countries)

               foreach (var name in item.Racers)

                   Console.Write("{0}; ", name);

               Console.WriteLine();

UK         9

Jim Clark; Lewis Hamilton; Mike Hawthorn; Graham Hill; Damon Hill; James Hunt; N

igel Mansell; Jackie Stewart; John Surtees;

Brazil     3

Emerson Fittipaldi; Nelson Piquet; Ayrton Senna;

Finland    3

Mika Hakkinen; Kimi R?ikk?nen; Keke Rosberg;

Australia  2

Jack Brabham; Alan Jones;

Austria    2

Niki Lauda; Jochen Rindt;

Italy      2

Alberto Ascari; Nino Farina;

USA        2

Mario Andretti; Phil Hill;

連接配接:

使用join字句可以根據特定的條件合并兩個資料源,但之前要獲得兩個要連接配接的清單。在一級方程式比賽中,有賽手冠軍和車隊冠軍。賽手從GetContructorChampions ()方法中傳回,現在要獲得一個年份清單,列出賽手冠軍和車隊冠軍。為此,先定義兩個查詢,用于查詢賽車和車隊。

var racers = from r in Formula1.GetChampions()

                        from y in r.Years

                        where y > 2003

                        select new

                        {

                            Year = y,

                            Name = r.FirstName + " " + r.LastName

                        };

    var teams = from t in

                           Formula1.GetContructorChampions()

                       from y in t.Years

                       where y > 2003

                       select new

                       {

                           Year = y,

                           Name = t.Name

                       };

有了這兩個查詢,再通過字句join r in teams on r.Year equals t.Year,根據賽手獲得冠軍的年份和車隊獲得冠軍的年份進行連接配接。Select字句定義了一個新的匿名類型,它包含Year、Racer和Team屬性

var racersAndTeams =

                 from r in racers

                 join t in teams on r.Year equals t.Year

                 select new

                     Year = r.Year,

                     Racer = r.Name,

                     Team = t.Name

                 };

把上述合并成一個Linq查詢語句

           var racersAndTeams = from r in

from r1 in Formula1.GetChampions() from yr in r1.Years

                               where yr > 2003

                                 select new

                                 {

                                           Year = yr,

                                    Name = r1.FirstName + " " + r1.LastName

                                 }

                                join t in

from t1 in Formula1.GetContructorChampions()  from yt in t1.Years

                                where yt > 2003

                                select new

                                      Year = yt,

                                      Name = t1.Name

                               on r.Year equals t.Year

                                {

                                    Year=r.Year,

                                    Racer=r.Name,

                                    Team=t.Name

                                };          

Console.WriteLine("Year  Champion " + "Constructor Title");

           foreach (var item in racersAndTeams)

               Console.WriteLine("{0}: {1,-20} {2}",

                  item.Year, item.Racer, item.Team);

Year  Champion Constructor Title

2004: Michael Schumacher   Ferrari

2005: Fernando Alonso      Renault

2006: Fernando Alonso      Renault

2007: Kimi R?ikk?nen       Ferrari

2008: Lewis Hamilton       Ferrari

集合操作:

擴充方法Distinct()、Union()、Intersect()和Except()都是集合操作。下面建立一個駕駛法拉利的以及方程式冠軍序列和駕駛邁凱輪的一級方程式冠軍序列,然後确定是否有駕駛法拉利和邁凱輪的冠軍。當然可以使用Intersect()擴充方法。

擷取所有駕駛法拉利的冠軍:

var ferrariDrivers = from r in Formula1.GetChampions()

                               from c in r.Cars

                               where c == "Ferrari"

                               orderby r.LastName

                                   select r;

寫一個公共的方法來擷取所有駕駛邁凱輪的冠軍

private static IEnumerable<Racer> GetRacerByCar(string car)

{

          return from r in Formula1.GetChampions() from c in r.Cars where c==car orderby r.LastName select r;

             因為不在其他的地方使用,是以定義一個委托類型的變量來儲存Linq查詢。racerByCar變量必須是一個委托類型,該委托類型需要一個字元串參數,并傳回IEnumerable<Racer>,類似前面實作的方法。為此,定義了幾個泛型委托Fun<>,是以不需要聲明自己的委托。把一個Lambda表達賦予racerByCar變量。Lambda表達式的左邊定義了一個car的變量,其類型是Func委托(字元串)的第一個泛型參數。右邊定義了Linq查詢,它使用該參數和Where字句:

Func<string, IEnumerable<Racer>> racersByCar =

               car => from r in Formula1.GetChampions()

                      from c in r.Cars

                      where c == car

                      orderby r.LastName

                      select r;

           Console.WriteLine("World champion with Ferrari and McLaren");

           foreach (var racer in racersByCar("Ferrari").Intersect(racersByCar("McLaren")))

World champion with Ferrari and McLaren

合并

                     Zip()方法是.Net新增的,允許用一個謂詞函數把兩個相關的序列合并一個。首先建立兩個相關的序列,他們使用相同的篩選和排序方法。對于合并,這個很重要,因為第一個集合中的第一項會與第二個集合中的第一項合并,第一個集合中的第二項與第二個集合中的第二項合并,以此類推。如果兩個序列不相同,Zip()就在較小的集合的末尾時停止。

               第一個集合中的元素有一個Name屬性,第二個集合元素有LastName和Starts兩個屬性。

               在racerName是集合上使用Zip()方法,需要把第二個集合(racerNameAndStarts)作為第一個參數。第二個參數的類型是Func<TFirst,TSecond,TResult>。這個參數實作為一個Lambda表達式,它通過參數first接收第一個集合的元素,通過參數second接收第二個集合元素,其實作代碼建立并傳回一個字元串,該字元串包含第一個集合中元素的Name屬性和第二個集合中元素的Starts屬性:

 var racerNames = from r in Formula1.GetChampions()

                            where r.Country == "Italy"

                            orderby r.Wins descending

                            select new

                            {

                                Name = r.FirstName + " " + r.LastName

                            };

           var racerNamesAndStarts = from r in Formula1.GetChampions()

                                  where r.Country == "Italy"

                                  orderby r.Wins descending

                                  select new

                                  {

                                      LastName = r.LastName,

                                      Starts = r.Starts

                                  };

Alberto Ascari, starts: 32

Nino Farina, starts: 33

           var racers = racerNames.Zip(racerNamesAndStarts, (first, second) => first.Name + ", starts: " + second.Starts);      

           foreach (var r in racers)

               Console.WriteLine(r);

分區

         擴充方法Take()和Skip()等的分區操作可用于分頁,例如顯示5×5賽手

例:Skip方法先忽略根據頁面大小和實際頁數計算出的項數,在使用Take()方法根據頁面大小提取一定數量的項;

int pageSize = 5;

           int numberPages = (int)Math.Ceiling(Formula1.GetChampions().Count() /

                 (double)pageSize);

           for (int page = 0; page < numberPages; page++)

               Console.WriteLine("Page {0}", page);

               var racers =

                  (from r in Formula1.GetChampions()

                   orderby r.LastName

                   select r.FirstName + " " + r.LastName).

                  Skip(page * pageSize).Take(pageSize);

               foreach (var name in racers)

                   Console.WriteLine(name);

Page 0

Fernando Alonso

Mario Andretti

Alberto Ascari

Jack Brabham

Jim Clark

Page 1

Nino Farina

Emerson Fittipaldi

Mika Hakkinen

Lewis Hamilton

Page 2

Graham Hill

Damon Hill

Denny Hulme

Page 3

James Hunt

Alan Jones

Nigel Mansell

Nelson Piquet

Page 4

Alain Prost

Jochen Rindt

Keke Rosberg

Page 5

Ayrton Senna

Jackie Stewart

Jacques Villeneuve

聚合操作符

  聚合操作符(如:count(),Sum(),Min(),Max(),Average()和Aggregate())傳回的是一個值。

下面的Count()用于Racer的Years屬性。傳回冠軍詞素超過3次的賽手。

    var query = from r in Formula1.GetChampions()

                       where r.Years.Count() > 3

                       orderby r.Years.Count() descending

                           Name = r.FirstName + " " + r.LastName,

                           TimesChampion = r.Years.Count()

           foreach (var r in query)

               Console.WriteLine("{0} {1}", r.Name, r.TimesChampion);

結果:Michael Schumacher 7

Juan Manuel Fangio 5

Alain Prost 4

Sum()方法彙總序列中的所有數字,傳回這些數字的和,下面是Sun()方法用于計算一個國家的赢得比賽的總次數。首先根據國家對賽手的分組,再在新建立的匿名類型中,把Wins屬性賦予某個國家赢得的總次數。

var countries = (from c in  from r in Formula1.GetChampions() group r by r.Country into c   select new

                Country = c.Key,

                Wins = (from r1 in c select r1.Wins).Sum()

                            orderby c.Wins descending, c.Country

                            select c).Take(5);

           foreach (var country in countries)

               Console.WriteLine("{0} {1}", country.Country, country.Wins);

結果:UK 147

Germany 91

Brazil 78

France 51

Finland 42

轉換:

    在疊代中使用查詢時,查詢就會執行。而使用轉換操作符會立即執行查詢,把查詢結果放在數組清單或字典中。

例:調用ToList擴充方法,立即執行查詢,得到的結果放在List<T>類中。

               List<Racer> racers=(from r in Formula1.GetChampions() where r.Starts>150 orderby r.Starts descending select r).ToList();

               Foreach( var racer in racers)

                     Console.WriteLine(“{0}  {0:S}”,racer);

          把傳回的對象放在清單中并沒有這麼簡單。例如,對于集合中從賽車到賽車手的快速通路,可以使用新類Lookup<TKey,TElement>。

          注:Dictionary<TKey,Tvalue>類隻支援一個鍵對應一個值。在System.Linq命名空間的類Lookup<TKey,TElement>類中,一個鍵可以對應多個值。

使用符合的from查詢,可以攤平賽手和賽車序列,建立帶有Car和Racer屬性的匿名類型。在傳回的Lookup對象中,鍵的類型影視表示汽車的string,值的類型影視Racer。為了驚醒這個選擇,可以給ToLookup()方法的重載版本傳遞一個鍵和一個元素選擇器。鍵選擇器引用Car屬性,元素選擇器引用Racer屬性。

    var racers = (from r in Formula1.GetChampions()

                         from c in r.Cars

                         select new

                         {Car =c,

                         Racer=r}).ToLookup(cr=>cr.Car,cr=>cr.Racer);

           if (racers.Contains("Williams"))

               foreach (var williamsRacer in racers["Williams"])

                   Console.WriteLine(williamsRacer);

結果:Alan Jones

如果需要在非類型化的集合上(如ArrayList),使用Linq查詢,就可以用Cast()方法。例:基于Object類型的ArrayList集合用Racer對象填充。為了定義強類型的查詢,可以使用Cast()方法。

var list = new System.Collections.ArrayList(Formula1.GetChampions() as System.Collections.ICollection);

           var query = from r in list.Cast<Racer>()

                       where r.Country == "USA"

           foreach (var racer in query)

               Console.WriteLine("{0:A}", racer);

輸出結果:

Mario Andretti, USA; starts: 128, wins: 12

Phil Hill, USA; starts: 48, wins: 3

生成操作符。

                生成操作Range(),Empty()和Repear()不是擴充方法,而是傳回序列的正常靜态方法。在Linq to object中,這些方法用于Enumerable類。有時需要填充一個範圍的數字,此時就應使用Range()方法。這個方法把第一個參數作為起始值,把第二個參數作為要填充的項數。

var values=Enumerable.Range(1,20);

foreach( var item in values)

           Console.Write(“{0}”,item);

結果:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

注:Range() 方法不傳回填充了所定義值的集合,這個方法與其他方法一樣,也推遲執行查詢,并傳回一個RangeEnumerator,其中隻有一條yield return語句,來遞增。可以把該結果與擴充方法合并起來獲得另一個結果,例:Select()擴充方法

Var values=Enumerable.Range(1,20).Select(n=>n*3);

Empty()方法傳回一個不傳回值的疊代器,它可以用于需要一個集合的參數,其中可以給參數穿空集合。

Repeat()方法傳回一個疊代器,該疊代器把同一個值重複特定的次數。

15、Linq 實作sql中的not in和in條件查詢

1、in條件查詢

var queryResult = from p in db.Products

where (new int?[] {1,2}).Contains(p.CategoryID)

select p;

2、not in條件查詢

var queryResult = from p in db.Products

where ! (new int?[] {1,2}).Contains(p.CategoryID)