LINQ标准查询操作符学习笔记三

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);
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值