11、分区

扩展方法Take()和Skip()等用于分区操作,这些操作可用于数据分页。在下面的Linq查询中,把扩展方法添加到查询最后,Skip()方法或略掉根据分页大小和页数得到的项数,Take()方法根据分页大小提取一定数目的项:

  1. int pagesize = 5;  
  2. int numberPages = (int)Math.Ceiling(Formula1.GetChampions().Count / (double)pagesize);//获得页数  
  3.   
  4. for (int i = 0; i < numberPages; i++)  
  5. {  
  6.     Console.WriteLine("Page {0}", i);  
  7.     var racers = (from r in Formula1.GetChampions()  
  8.                   orderby r.LastName  
  9.                   select r.FirstName + " " + r.LastName)  
  10.                       .Skip(i * pagesize) //跳过指定数目的元素  
  11.                       .Take(pagesize)  //提取指定数目的元素?  
  12.                       .TakeWhile(r => r.Length > 11);  //额外的限制条件  
  13.     foreach (var item in racers)  
  14.     {  
  15.         Console.WriteLine(item);  
  16.     }  
  17.     Console.WriteLine();  
  18. }  
Math.Ceiling (Decimal) 返回大于或等于指定的十进制数的最小整数。
Math.Ceiling (Double) 返回大于或等于该指定双精度浮点数的最小整数。

输出结果是几组赛手。

       12、聚合操作

聚合操作用于对集合项进行简单的运算,返回结果是一个值而不是一组数据。

下面演示使用Count()方法筛选出冠军次数操作3的赛手:

  1. //统计获得冠军次数大于3次的运动员和获胜次数  
  2. var query = from r in Formula1.GetChampions()  
  3.             where r.Years.Count() > 3  
  4.             orderby r.Years.Count() descending  
  5.             select new  
  6.             {  
  7.                 Name = r.FirstName + " " + r.LastName,  
  8.                 TimesChampion = r.Years.Count()  
  9.             };  
  10. foreach (var item in query)  
  11. {  
  12.     Console.WriteLine(item.Name + " " + item.TimesChampion.ToString());  
  13. }  
  14. Console.WriteLine();  

又如Sum()方法,返回序列中的所有数字的和。下面的示例演示了使用Sum()方法计算一个国际赢得的比赛次数,首先根据国家对赛手分组,在创建的匿名类中,对Wins属性进行计算:

  1. //计算一个国际获得冠军的总次数  
  2.             var countries =  
  3.                 from c in  
  4.                     from r in Formula1.GetChampions()  
  5.                     group r by r.Country into c1  
  6.                     select new  
  7.                     {  
  8.                         Country = c1.Key,  
  9.                         Wins = (from r1 in c1 select r1.Wins).Sum()  
  10.                     }  
  11.                 orderby c.Wins descending  
  12.                 select c;  

       13、结果转换

查询结果可以通过调用扩展方法转换成其他类型。但是需要注意的是,如果进行了类型转换,Linq查询将会立即执行而不是推迟到访问数据项时才执行。

下面是一个简单的例子:

  1. //简单查询  
  2. var query = (from r in Formula1.GetChampions()  
  3.              where r.Starts > 150  
  4.              orderby r.Starts descending  
  5.              select r).ToList();  
  6. foreach (var item in query)  
  7. {  
  8.     Console.WriteLine("{0} {0:S}",item);  
  9. }  
  10. Console.WriteLine();  
  11.   
  12. //扩展方法查询  
  13. var query2 = Formula1.GetChampions()  
  14.     .Where(r => r.Starts > 150)  
  15.     .OrderByDescending(r => r.Starts)  
  16.     .ToList()  
  17.     .Select(r => r) ;  
  18. foreach (var item in query2)  
  19. {  
  20.     Console.WriteLine("{0} {0:S}", item);  
  21. }  
  22. Console.WriteLine();  
  23. //生成查找表  
  24. var query3 = (from r in Formula1.GetChampions()  
  25.               from c in r.Cars  
  26.               select new { Car = c, Racer = r })  
  27.                   .ToLookup(cr => cr.Car, cr => cr.Racer);  
  28. if (query3.Contains("Williams"))  
  29. {  
  30.     foreach (var item in query3["Williams"])  
  31.     {  
  32.         Console.WriteLine(item);  
  33.     }  
  34. }  

这里建查询结果使用ToList()方法转换成了List<T>类型。

       14、生成操作符

生成操作符Ranger()、Empty()、Repear()不是扩展方法,而是返回序列的正常静态方法。

下面例子返回一个填充了一个范围数字的变量,使用了Ranger()方法对变量进行填充

  1. //var values = Enumerable.Range(1, 12);  
  2. var values = Enumerable.Range(1, 12)  
  3.     .Where(r=>r%2 == 0)  
  4.     .Select(r => r * 2);  
  5. foreach (var item in values)  
  6. {  
  7.     Console.Write("{0} ",item);  
  8. }  
  9. Console.WriteLine();  


提示:Range()方法不返回填充了所定义值的集合,这个方法与其他方法一样,也推迟执行查询,返回一  个RangeEnumerator,其中只有一个yield return 语句,来递增值。 
可以把该结果与其他扩展方法合并起来,获得另一个结果,例如使用Select()扩展方法: 
Empty()方法返回一个不返回值的迭代器,它可以用于参数需要一个集合,且可以给参数传送空集合的情形。 
Repeat()方法返回一个迭代器,该迭代器把同一个值重复特定的次数。

       15、并行Linq

并行Linq是.Net4新增加的。在.Net 4的System.Linq命名空间中新增加了类ParallelEnumerable,可以分解查询工作使其工作在多个线程上。

这里首先准备一个大型集合,用随机数填充之后使用Linq筛选数据,获取筛选数据的总和。该查询使用where子句定义一个筛选器,汇总值小于20的项,最后使用Sum()方法计算: 

  1. const int arraySize = 100000000;  
  2. var data = new int[arraySize];  
  3. var r = new Random();  
  4. for (int i = 0; i < arraySize; i++)  
  5. {  
  6.     data[i] = r.Next(40);  
  7. }  
  8. var sum = (from x in data.AsParallel()  
  9.           where arraySize < 20  
  10.           select x).Sum();  
  11. sum = data.AsParallel().Where(x => x > 20).Select(x => x).Sum();  
  12. Console.WriteLine(sum);  

可以看出,这里的查询与前面的查询仅仅是使用了AsParallel()方法。

运行这段代码时启动任务管理器就可以看见效果了。此时系统上所有的CPU都处于忙碌状态,如果删除了AsParallel方法,就不会有这个效果了。

 示例代码:https://files.cnblogs.com/zyqgold/MyLinqTest.rar