6、对筛选结果进行分组

使用group子句和GroupBy()扩展方法可以对查询结果进行分组。下边的例子是将赛车冠军按照国家进行分组,并列出一个国家赛车冠军的总数:

  1. //简ò单蹋inq分?组哩?  
  2. var query = from r in Formula1.GetChampions()  
  3.             group r by r.Country into g  
  4.             orderby g.Count() descending, g.Key  
  5.             where g.Count() >= 2  
  6.             select new  
  7.             {  
  8.                 Country = g.Key,  
  9.                 Count = g.Count()  
  10.             };  

子句group r by r.Country into g 根据Country属性组合所有赛车手到一个新的标识符g中。g用于以后访问分组的结果信息。group子句的结果根据扩展方法Count()的结果进行 排序。Select子句创建了一个带Country和Count属性的匿名类型。这里有一个对象需要注意:g.Key。这指的是是group方法筛选的依 据,本例中g.Key就是分组依据Country。

直接使用扩展方法中的GroupBy()和ThenBy()方法也可以实现相应的筛选功能:

  1. var query = Formula1.GetChampions()  
  2.     .GroupBy(r => r.Country)  
  3.     .OrderByDescending(g => g.Count())  
  4.     .ThenBy(g => g.Key)  
  5.     .Where(g => g.Count() >= 2)  
  6.     .Select(g => new { Country = g.Key, Count = g.Count() });  

 这里可以看出子句group r by r.Country into g被解析为GroupBy(r=>r.Country),返回分组序列,之后进行了排序和筛选等见大的操作即得到了需要的结果。

       7、对嵌套对象进行分组

如果分组的对象应包含嵌套的序列,就可以改变select子句创建的匿名类型。先看下面的代码:

  1. var countrys =  
  2.     from r in Formula1.GetChampions()  
  3.     group r by r.Country into g   //g是?按恪?照?国ú别纄分?组哩?后ó的?Formula1.GetChampions()  
  4.     orderby g.Count() descending, g.Key  //g.Key指?的?是?分?组哩?依皑?据Yr.Country 即′r中D的?Country  
  5.     where g.Count() >= 2  
  6.     select  
  7.     new  
  8.     {  
  9.         Country = g.Key,  
  10.         Count = g.Count(),  
  11.         Racer = from r1 in g  
  12.                 orderby r1.LastName  
  13.                 select r1.FirstName + "  " + r1.LastName  
  14.     };  

在上面的例子中,返回的国家不仅包含国家名和赛手数量这两个属性,还包括赛手姓名序列。这个序列用一个赋予Racers属性的from/in内部子句指定,内部的from子句使用分组标识符g获取该分组中的所有赛车手,并排序,再根据姓名创建一个新的字符串返回。

这段代码转换成扩展方法可表示如下:

  1. var countrys = Formula1.GetChampions()  
  2.     .GroupBy(r => r.Country)  
  3.     .OrderByDescending(g => g.Count())  
  4.     .ThenBy(g => g.Key)  
  5.     .Where(g => g.Count() >= 2)  
  6.     .Select(g => new  
  7.     {  
  8.         Country = g.Key,  
  9.         Count = g.Count(),  
  10.         Racer = g.OrderBy(r => r.LastName).Select(r => r.FirstName + " " + r.LastName)  
  11.     });  

        8、连接查询

使用join子句可以根据特定的条件合并两个数据源,但之前要获得两个要连接的列表。

在一级方程式比赛中,有比赛冠军和车队冠军,下边的代码用来筛选出每年的赛手冠军和车队冠军。实现这一功能有几种方法,下面一一列举:

(1)使用多次查询

先定义两个查询,分别找出2003年之后每年的赛手冠军和车队冠军:

  1. //1、查询1 var racer = from r in Formula1.GetChampions()  
  2.             from y in r.Years  
  3.             where y > 2003  
  4.             select new  
  5.             {  
  6.                 Year = y,  
  7.                 Name = r.FirstName + " " + r.LastName  
  8.             };  
  1. //2、查询2 var teams = from t in Formula1.GetConstructorChampions()  
  2.             from y in t.Years  
  3.             where y > 2003  
  4.             select new  
  5.             {  
  6.                 Year = y,  
  7.                 Name = t.Name  
  8.             };  

之后在通过join in …on…进行连接:

  1. //3、将两次查询结果连接  
  2. var query = from r in racer  
  3.             join t in teams on r.Year equals t.Year  
  4.             select new  
  5.             {  
  6.                 Year = r.Year,  
  7.                 Racer = r.Name,  
  8.                 Team = t.Name  
  9.             };  

(2)也可将两次查询合并为一个Linq查询 ,不过比较麻烦的说:

  1. //使用一条语句完成所有连接查询  
  2. var query2 = from r in  
  3.                  from r1 in Formula1.GetChampions()  
  4.                  from yr in r1.Years  
  5.                  where yr > 2003  
  6.                  select new  
  7.                  {  
  8.                      Year = yr,  
  9.                      Name = r1.FirstName + " " + r1.LastName  
  10.                  }  
  11.              join t in  
  12.                  from t1 in Formula1.GetConstructorChampions()  
  13.                  from yt in t1.Years  
  14.                  where yt > 2003  
  15.                  select new  
  16.                  {  
  17.                      Year = yt,  
  18.                      Name = t1.Name  
  19.                  }  
  20.              on r.Year equals t.Year  
  21.              select new  
  22.              {  
  23.                  Year = r.Year,  
  24.                  Racer = r.Name,  
  25.                  Team = t.Name  
  26.              };  

       9、集合查询

System.Linq中的扩展方法Distinct()、Union()、Intersect()、Except()的都是集合操作的方法。这些方法使用不难,主要涉及到一些对集合操作的理解上。

下面用一段代码演示集合操作符的使用:

  1. //1、先进性一次简单的查询  
  2. var query = from r in Formula1.GetChampions()  
  3.             from y in r.Years  
  4.             where y > 2003  
  5.             select r;  
  6. //2、再对结果进行集合操作.这里的几个操作没有实际意义,只是为了演示用法。    
  7.  var q = query.Union(query).Distinct().Intersect(query);  
  8.                                                                    

上面的代码中,先进行了一个间的的查询,之后对查询结果进行了集合操作。以下是上面代码转换成使用扩展方法的代码:

  1. //3、直接使用扩展方法进行查询  
  2.            var query2 = Formula1.GetChampions()  
  3.                .SelectMany(r => r.Years, (r, y) => new { Racer = r, Year = y })   //使用了SelectMany()嵌套查询  
  4.                .Where(r => r.Year > 2003)  
  5.                .Select(r => r.Racer)  
  6.                .Union(query).Distinct().Intersect(query);   //仅演示,没实际意义  

       10、合并

合并操作Zip()是.NET4新增的。这个操作运行用一个谓词函数把两个相关的序列合并为一个。我不是很理解这个合并操作,仅给出树上的代码,不做解释:

    1. var racerNames = from r in Formula1.GetChampions()  
    2.                  where r.Country == "Italy"  
    3.                  orderby r.Wins descending  
    4.                  select new  
    5.                  {  
    6.                      Name = r.FirstName + " " + r.LastName  
    7.                  };  
    8. var racerNameAndStarts = from r in Formula1.GetChampions()  
    9.                          where r.Country == "Italy"  
    10.                          orderby r.Wins descending  
    11.                          select new  
    12.                          {  
    13.                              LastName = r.LastName,  
    14.                              Starts = r.Starts  
    15.                          };  
    16. //.Net4中的Zip()方法。用一个谓词函数把两个相关的序列合并为一个。注意Zip的参数  
    17. var racers = racerNames.Zip(racerNameAndStarts, (first, second) => first.Name + ",starts " + second.Starts);  
    18. foreach (var item in racers)  
    19. {  
    20.     Console.WriteLine(item);