6、对筛选结果进行分组
使用group子句和GroupBy()扩展方法可以对查询结果进行分组。下边的例子是将赛车冠军按照国家进行分组,并列出一个国家赛车冠军的总数:
- //简ò单蹋inq分?组哩?
- var query = 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()
- };
子句group r by r.Country into g 根据Country属性组合所有赛车手到一个新的标识符g中。g用于以后访问分组的结果信息。group子句的结果根据扩展方法Count()的结果进行 排序。Select子句创建了一个带Country和Count属性的匿名类型。这里有一个对象需要注意:g.Key。这指的是是group方法筛选的依 据,本例中g.Key就是分组依据Country。
直接使用扩展方法中的GroupBy()和ThenBy()方法也可以实现相应的筛选功能:
- var query = 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() });
这里可以看出子句group r by r.Country into g被解析为GroupBy(r=>r.Country),返回分组序列,之后进行了排序和筛选等见大的操作即得到了需要的结果。
7、对嵌套对象进行分组
如果分组的对象应包含嵌套的序列,就可以改变select子句创建的匿名类型。先看下面的代码:
- var countrys =
- from r in Formula1.GetChampions()
- group r by r.Country into g //g是?按恪?照?国ú别纄分?组哩?后ó的?Formula1.GetChampions()
- orderby g.Count() descending, g.Key //g.Key指?的?是?分?组哩?依皑?据Yr.Country 即′r中D的?Country
- where g.Count() >= 2
- select
- new
- {
- Country = g.Key,
- Count = g.Count(),
- Racer = from r1 in g
- orderby r1.LastName
- select r1.FirstName + " " + r1.LastName
- };
在上面的例子中,返回的国家不仅包含国家名和赛手数量这两个属性,还包括赛手姓名序列。这个序列用一个赋予Racers属性的from/in内部子句指定,内部的from子句使用分组标识符g获取该分组中的所有赛车手,并排序,再根据姓名创建一个新的字符串返回。
这段代码转换成扩展方法可表示如下:
- var countrys = 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(),
- Racer = g.OrderBy(r => r.LastName).Select(r => r.FirstName + " " + r.LastName)
- });
8、连接查询
使用join子句可以根据特定的条件合并两个数据源,但之前要获得两个要连接的列表。
在一级方程式比赛中,有比赛冠军和车队冠军,下边的代码用来筛选出每年的赛手冠军和车队冠军。实现这一功能有几种方法,下面一一列举:
(1)使用多次查询
先定义两个查询,分别找出2003年之后每年的赛手冠军和车队冠军:
- //1、查询1 var racer = from r in Formula1.GetChampions()
- from y in r.Years
- where y > 2003
- select new
- {
- Year = y,
- Name = r.FirstName + " " + r.LastName
- };
- //2、查询2 var teams = from t in Formula1.GetConstructorChampions()
- from y in t.Years
- where y > 2003
- select new
- {
- Year = y,
- Name = t.Name
- };
之后在通过join in …on…进行连接:
- //3、将两次查询结果连接
- var query = from r in racer
- join t in teams on r.Year equals t.Year
- select new
- {
- Year = r.Year,
- Racer = r.Name,
- Team = t.Name
- };
(2)也可将两次查询合并为一个Linq查询 ,不过比较麻烦的说:
- //使用一条语句完成所有连接查询
- var query2 = 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.GetConstructorChampions()
- from yt in t1.Years
- where yt > 2003
- select new
- {
- Year = yt,
- Name = t1.Name
- }
- on r.Year equals t.Year
- select new
- {
- Year = r.Year,
- Racer = r.Name,
- Team = t.Name
- };
9、集合查询
System.Linq中的扩展方法Distinct()、Union()、Intersect()、Except()的都是集合操作的方法。这些方法使用不难,主要涉及到一些对集合操作的理解上。
下面用一段代码演示集合操作符的使用:
- //1、先进性一次简单的查询
- var query = from r in Formula1.GetChampions()
- from y in r.Years
- where y > 2003
- select r;
- //2、再对结果进行集合操作.这里的几个操作没有实际意义,只是为了演示用法。
- var q = query.Union(query).Distinct().Intersect(query);
上面的代码中,先进行了一个间的的查询,之后对查询结果进行了集合操作。以下是上面代码转换成使用扩展方法的代码:
- //3、直接使用扩展方法进行查询
- var query2 = Formula1.GetChampions()
- .SelectMany(r => r.Years, (r, y) => new { Racer = r, Year = y }) //使用了SelectMany()嵌套查询
- .Where(r => r.Year > 2003)
- .Select(r => r.Racer)
- .Union(query).Distinct().Intersect(query); //仅演示,没实际意义
10、合并
合并操作Zip()是.NET4新增的。这个操作运行用一个谓词函数把两个相关的序列合并为一个。我不是很理解这个合并操作,仅给出树上的代码,不做解释:
- var racerNames = from r in Formula1.GetChampions()
- where r.Country == "Italy"
- orderby r.Wins descending
- select new
- {
- Name = r.FirstName + " " + r.LastName
- };
- var racerNameAndStarts = from r in Formula1.GetChampions()
- where r.Country == "Italy"
- orderby r.Wins descending
- select new
- {
- LastName = r.LastName,
- Starts = r.Starts
- };
- //.Net4中的Zip()方法。用一个谓词函数把两个相关的序列合并为一个。注意Zip的参数
- var racers = racerNames.Zip(racerNameAndStarts, (first, second) => first.Name + ",starts " + second.Starts);
- foreach (var item in racers)
- {
- Console.WriteLine(item);
- }