首页 > 代码库 > C#基础:LINQ 查询函数整理
C#基础:LINQ 查询函数整理
1、LINQ 函数
1.1、查询结果过滤 :where()
1 public static IEnumerbale<TSouce> Where<TSource>(this IEnumerable<Tsource> source,Func<TSource,bool> predicate); 2 public static IEnumerable<TSource>where<TSource> (this IEnumerable<TSource> source,Func<TSource,int,bool> predicate);
Where() 的参数是用来过滤元素的条件,它要求条件必须传回bool,以确定此元素是否符合条件,或是由特定的元素开始算起(使用Func<TSource,int bool>,中间的传入参数代表该元素在集合中的索引值),例如要在一个数列集合中找出大于5的数字时:
1 List<int> list1=new List<int>(){6,4,2,7,9,0}; 2 3 list1.Where(c=>c>5);
或者
1 list1.Where(c=>c>=1).Where(c=>c<=5); 2 3 list1.Where(c=>c>=1&&c<=5);
1.2、选取数据: Select()、SelectMany()
1 public static IEnumerable<TResult> Select<TSource,TResult>(this IEnumerable<TSource> source,Func<TSource,TResult> selector); 2 public static IEnumerable<TResult> Select<TSource,TResult>(this IEnumerable<TSource> source,Func<TSource,int,TResult> selector);
与Where() 类似,Select() 也可以按照元素所在的位置判断处理,而Select()所指定的处理式selector 必须传回一个对象,这个对象可以是现有的类型,也可以是匿名的类型,既可以通过Select() 来重新组装所需数据。例:
1 var query=db.OrderDetails.Where(o=>o.ID==12345).Select(o=>new{ ProductID=o.ProductID,Qty=o.Qty});
Select() 的另一个相似函数SelectMay() 则是处理有两个集合对象来源的数据选取,其原型如下:
1 public static IEnumerable<TResult> SelectMany<TSource,TResult>(this IEnumerable<TSource> source,Func<TSource,IEnumberable<TResult>> selector); 2 public static IEnumerable<TResult> SelectMany<TSource,TResult>(this IEnumerable<TSource> source,Func<TSource,int,IEnumberable<TResult>> selector); 3 public static IEnumerable<TResult> SelectMany<TSource,TCollection,TResult>(this IEnumerable<TSource> source,Func<TSource,IEnumberable<TCollection>> collectionSelector,Func<TSource,TCollection,TResult> resultSelector); 4 public static IEnumerable<TResult> SelectMany<TSource,TCollection,TResult>(this IEnumerable<TSource> source,Func<TSource,int,IEnumberable<TCollection>> collectionSelector,Func<TSource,TCollection,TResult> resultSelector);
SelectMany() 在LINQ 函数调用上较难理解,但如果把它想象成数据库的CROSS JOIN ,相对来说就容易懂了,例:
1 List<int> list1=new List<int>(){1,2,3,4,5,6}; 2 List<int> list2=new List<int>(){6,4,2,7,9,0}; 3 4 var query=list1.SelectMany(o=>list2); 5 foreach(var q in query) 6 Console.WriteLine("{0}",q);
输出结果:
1 6424790642790642790642790642790642790
因为“642790”输出了 6次,list1 内的元素是6个,所以可以知道SelectMany() 会按照list1 内的元素个数调用它的selector,并组装集合输出。
1.3、群组数据:GroupBy()、ToLookup()
1 List<int> sequence =new List<int>(){1,2,3,4,3,2,4,6,4,2,4}; 2 3 var group=sequence.GroupBy(o=>o); 4 foreach(var g in group) 5 { 6 Console.WrilteLine("{0} count:{1}",g.Key,g.Count()); 7 /*计算每个数出现的次数。 8 GroupBy 设置了使用数列本身值作为Key值,并且利用这个Key 分组产生分组的数据(IGrouping<TKey,TElement类型),再对分组的数据进行汇总。结果如下: 9 10 1 count: 1 11 2 count: 3 12 3 count: 2 13 4 count: 4 14 6 count: 1 15 16 */
1 var nameValuesGroup=new[] 2 { 3 new{name="Allen", value=http://www.mamicode.com/65,group="A"}, 4 new{name="Abbey",value=http://www.mamicode.com/120,group="B"}, 5 new{name="Sue",Value=http://www.mamicode.com/200,group="A"} 6 }; 7 var lookupValues=namValuesGroup.ToLookup(c=>c.group); 8 foreach(var g in lookupValues) 9 { 10 Console.WriteLine("===Group: {0}===",g.Key); 11 foreach(var item in g) 12 { 13 Console.WriteLine("name:{0},value:{1}",item.name,item.value); 14 } 15 }
GroupBy()本身具有延迟执行的特性,而ToLookup()没有。
1.4、联接数据: Join() 与GroupJoin()
1 var query=from item1 in list1 2 join item2 in list2 on item1 equals item2 3 select item2; 4 var query3=list1.Join( 5 list2, 6 item1=>item1, 7 item2=>item2, 8 (item1,item2)=>item2 9 );
Enumerable<T>.Join()使用的是INNER JOIN 的概念,当TInner.Key 和TOuter.Key相同时,才会将元素输出到resultSelector 作为参数。
1 var query4=from item1 in list1 2 join item2 in list2 on item1 equals item2 into g 3 from item in g.DefaultIfEmpty() 4 select new{ v=item1,c=item}; 5 var query5=list1.GroupJoin( 6 list2, 7 item1=>item1, 8 item2=>item2, 9 (item1,item2)=>new {v=item1,c=item2.Count()});
1.5、数据排序:OrderBy() 与ThenBy()
1 var nameValues=new[] 2 { 3 new {name="Allen",value=http://www.mamicode.com/64}, 4 new {name="abbey",value=http://www.mamicode.com/120}, 5 new {name="slomng",value=http://www.mamicode.com/330}, 6 new {name="george",value=http://www.mamicode.com/213} 7 }; 8 //single sort 9 var sortedNames=nameValues.OrderBy(c=>c.name); 10 var sortedValues=nameValues.OrderBy(c=>c.value); 11 12 //multiply sort conditions 13 var sortedByNameValues=nameValues.OrderBy(c=>c.name).ThenBy(c=>c.value); 14 var sortedByValueNames=nameValues.OrderBy(c=>c.value).ThenBy(c=>c.name);
如果要设置多重排序条件,请务必使用OrderBy()加上ThenBy()的组合,若使用OrderBy +OrderBy 组合,会使得排序被执行两次,最终的结果会是最后一个OrderBy 所产生的的结果。
1.6、获取集合
1 var arrayOutput=nameValues.ToArray(); 2 var listOutput=nameValues.ToList(); 3 4 var dictOutput1=nameValues.ToDictionary(c=>c.name); 5 var dictOutput2=nameValues.ToDictionary(c=>c.name,c=>value);
1.7、划分并获取集合
1 public static IEnumberable<TSource> Skip<TSource>( 2 this IEnumerable<TSource> source, 3 int count 4 ) 5 public static IEnumberable<TSource> SkipWhile<TSource>( 6 this IEnumerable<TSource> source, 7 Func<TSource,bool> predicate 8 ) 9 public static IEnumberable<TSource> SkipWhile<TSource>( 10 this IEnumerable<TSource> source, 11 Func<TSource,int ,bool> predicate 12 ) 13 public static IEnumberable<TSource> Take<TSource>( 14 this IEnumerable<TSource> source, 15 int count 16 ) 17 public static IEnumberable<TSource> TakeWhile<TSource>( 18 this IEnumerable<TSource> source, 19 Func<TSource,bool> predicate 20 ) 21 public static IEnumberable<TSource> TakeWhile<TSource>( 22 this IEnumerable<TSource> source, 23 Func<TSource,int ,bool> predicate 24 )
Skip()用来在集合中跳跃,让LINQ 核心直接将游标跳到指定的位置,而不用通过“巡航”来移动,在大型集合中可节省不少时间,而SkipWhile 也有相同作用,但多了判断式,也就是跳过符合条件的元素,而不同的SkipWhile()可用来决定要跳过符合条件的或是判断跳过特定的索引值。
1.8、访问元素
1 var firstLastItems=new []{"zero","two","three","four","five"}; 2 string firstContainsO=firstLastItems.First(s=>s.Contains(‘o‘)); 3 string lastContainsO=firstLastItems.Last(s=>s.Contains(‘0‘));
LINQ 内还有一个Single,他会在集合中只有一个元素时传回该元素,但若集合是空的或是有两个以上的元素时会调用例外处理,或是使用它的姐妹方法SingleOrDefault 传回null值,实用性比fisrt和last 低。
1 var firstLastItems=new []{"zero","two","three","four","five"}; 2 string itematThree=firstLastITems.ElementAt(2);
若要判断集合内有没有特定值,LINQ 提供了Contains, 可以判断集合捏有没有传入的元素,但因为Contain 会判断对象是否相等,所以它另外提供了一个可传入IEqualityComparer<T> 的作为比较依据的重载(overload)方法,可用于自定义类对象的相等比较操作。
1.9、聚合与汇总
1 double myBalance=100.0; 2 3 int[] withdrawItems={20,10,40,50,10,70,30}; 4 5 double balance=withdrawItems.Aggregate(myBalance,(originbalance,nextWithdrawal)=>{ 6 Console.WriteLine("originbalance:{0},nextWithdrawak:{1}",originbalance,nextdrawal); 7 Console.WriteLine("Withdrawal status:{0}",(nextWithdrawal<=originbalance)>"OK":"FAILED"); 8 9 return ((nextWithdrawal<=originbalance)?(originbalance-nextWithdrawal):originbalance); 10 }); 11 Console.WriteLine("Ending balance:{0}:",balance);
若要对最终的存款值进行处理,即可使用第三个参数resultSelector,例:
1 var balanceStatus= 2 withdrawItems.Aggregate(myBalance,(originbalance,nextWithdrawal)=>{ 3 return((nextWithdrawal<=originbalance)?(originbalance-nextWithdrawal):originbalance); 4 5 }, 6 (finalbalance)=> 7 { 8 return (finalbalance>=1000)?"Normal":"Lower"; 9 });
2、标准的查询操作符
2.1 筛选
1 var racers=from r in Formula1.GetChampions() 2 where r.Wins > 15 && (r.Country=="Brazil"||r.Country=="Austria") 3 select r; 4 5 foreach(var r in racers) 6 { 7 Console.WriteLine("{0:A}",r); 8 }
下面使用Where() 和 Select() 的代码:
1 var racers=Formula1.GetChampions(). 2 Where(r=>r.Wins>15 && (r.Country=="Brazil" || r.Country=="Austria")). 3 Select(r=>r);
2.2 用索引筛选
1 var racers=Formula1.GetChamptions(). 2 Where((r,index)=>r.LastName.StartsWith("A") && index % 2 !=0); 3 4 foreach(var r in racers) 5 { 6 Console.WriteLine("{0,A}",r); 7 } 8
2.3 类型筛选
1 object[] data=http://www.mamicode.com/{"ones",1,3,"fre","fdfs",333}; 2 var query=data.OfType<string>(); 3 foreach(var s in query) 4 { 5 Console.WriteLine(s); 6 } 7 /* 8 运行结果为: 9 10 ones 11 fre 12 fdfs 13 */
2.4 复合的from 子句
1 var ferrariDrivers=from r in Formula.GetChampions() 2 from c in r.Cars 3 where c=="Ferrari" 4 orderby r.LastName 5 select r.FirstName +" "+ r.LastName;
1 public static IEnumerable<TResult> SelectMany<TSource,TCollection,TResult>(this IEnumerable<TSource> source,Func<TSource,IEnumberable<TCollection>> collectionSelector,Func<TSource,TCollection,TResult> resultSelector);
1 var ferrariDrivers= Formula1.GetChampion(). 2 SelectMany(r=>r.Cars, 3 (r,c)=>new{Racer=r,Car=c}. 4 where(r=>r.Car=="Ferrari"). 5 OrderBy(r=>r.Racer.LastName). 6 Select(r=>r.Racer.FirstName+" "+r.Racer.LastName));
2.5 排序
1 var racers=from r in Formula1.GetChampions() 2 where r.Country=="Brazil" 3 orderby r.Wins descending 4 select r;
1 var racers= Formula1.GetChampions(). 2 Where(r=>r.Country=="Brazil"). 3 OrderByDescending(r=>r.Wins). 4 Select(r=>r);
1 var racers=(from r in Formula1.GetChampions() 2 orderby r.Country,r.LastName,r.FirstName 3 select r).Take(10);
1 var racers=Formula1.GetChamptions(). 2 OrderBy(r=>r.Country). 3 ThenBy(r=>r.LastName). 4 ThenBy(r=>r.FirstName). 5 Take(10);
2.6 分组
1 var countries= from r in Formula1.GetChampions() 2 group r by r.Country into g 3 orderby g.Count() descending, g.Key 4 where g.Count() >=2 5 select new { 6 Country=g.Key, 7 Count=g.Count() 8 }; 9 foreach(var item in countries) 10 { 11 Console.WriteLine("{1,-10} {1}",item.Country,item.Count); 12 }
1 var countries= 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()});
2.7 对嵌套的对象分组
1 var countries=from r in Formula1.GetChampions() 2 group r by r.Country into g 3 orderby g.Count() descending, g.Key 4 where g.Count()>=2 5 select new 6 { 7 Country=g.Key, 8 Count=g.Count(), 9 Racers=from r1 in g 10 orderby r1.LastName 11 select r1.FirstName +" "+ r1.LastName 12 }; 13 foreach(var item in countries) 14 { 15 Console.WriteLine("{0,-10} {1}",item.Country,item.Count); 16 foreach(var name in item.Racers) 17 { 18 Console.WriteLine("{0};",name); 19 } 20 Console.WirteLine(); 21 }
2.8 内连接
1 var racers= from r in Formula1.GetChampions() 2 from y in r.Years 3 select new 4 { 5 Year=y, 6 Name=r.FirstName+" "+r.LastName 7 }; 8 9 vat teams=from t in Formula1.GetConstructorChampions() 10 from y in t.Years 11 select new 12 { 13 Year=y, 14 Name=t.Name 15 }; 16 var racersAndTeams=(from r in racers 17 join t in teams on r.Year equals t.Year 18 select new 19 { 20 r.Year, 21 Champion=r.Name, 22 Constructor=t.Name 23 }).Take(10); 24 Console.WriteLine("Year World Champion\t Constructor Title"); 25 foreach(var item in racersAndTeams) 26 { 27 Console.WriteLine("{0}:{1,-20} {2}",item.Year,item.Champion,item.Constructor); 28 }
1 var racersAndTeams=(from r in 2 from r1 in Formula1.GetChampions() 3 from yr in r1.Years 4 select new 5 { 6 Year=yr, 7 Name=r1.FirstName+" "+r1.LastName 8 } 9 join t in 10 from t1 in Formula1.GetConstructorChampions() 11 from yt in t1.Years 12 select new 13 { 14 Year=yt, 15 Name=t1.Name 16 } 17 on r.Year equals t.Year 18 orderby t.Year 19 select new 20 { 21 Year=r.Year, 22 Racer=r.Name, 23 Team=t.Name 24 }).Take(10);
2.9 左外连接
1 var racersAndTeams= 2 (from r in racers 3 join t in teams on r.Year equals t.Year into rt 4 from t in rt.DefaultIfEmpty() 5 orderby r.Year 6 select new 7 { 8 Year=r.Year, 9 Champion=r.Name, 10 Constructor=t==null?"no constructor championship":t.Name 11 }).Take(10);
2.10 组连接
1 public class Championship 2 { 3 public int Year{get;set;} 4 public string First{get;set;} 5 public string Second{get;set;} 6 public string Third{get;set;} 7 }
1 private static List<Championship> championships; 2 public static IEnumerable<Championship> GetChampionships() 3 { 4 if(championships == null) 5 { 6 championships=new List<Championship>(); 7 championships.Add(new Championship 8 { 9 Year=1950, 10 First="Nino Farina", 11 Second="Juan Manuel Fangio", 12 Third="Luigi Fagioli" 13 }); 14 championships.Add(new Championship 15 { 16 Year=1951, 17 First="Juan Manuel Fangio", 18 Second="Alberto Ascari", 19 Third="Froliab Gonzalez" 20 }); 21 }
1 public class RacerInfo 2 { 3 public int Year{get;set;} 4 public int Position {get;set;} 5 public string FirstName{get;set;} 6 public string LastName{get;set;} 7 }
1 var racers=Formula1.GetChampionships() 2 .SelectMany(cs=>new List<RacerInfo>() 3 { 4 new RacerInfo{ 5 Year=cs.Year, 6 Position=1, 7 FirstName=cs.First.FirstName(), 8 LastName=cs.Last.LastName() 9 }, 10 new RacerInfo{ 11 Year=cs.Year, 12 Position=2, 13 FirstName=cs.Fisrt.FirstName(), 14 LastName=cs.Last.LastName() 15 }, 16 new RacerInfo{ 17 Year=cs.Year, 18 Position=3, 19 FirstName=cs.First.FirstName(), 20 LastName=cs.Last.LastName() 21 } 22 });
1 public static class StringExtension 2 { 3 public static string FirstName(this string name) 4 { 5 int ix=name.LastIndexOf(‘ ‘); 6 return name.Substring(0,ix); 7 } 8 public static string LastName(this string name) 9 { 10 int ix=name.LastIndexOf(‘ ‘); 11 return name.Substring(ix+1); 12 } 13 }
1 var q=(from r in Formula1.GetChampions() 2 join r2 in racers on 3 new 4 { 5 FirstName=r.FirstName, 6 LastName=r.LastName 7 } 8 equals 9 new 10 { 11 FisrtName=r2.FirstName, 12 LastName=r2.LastName 13 } 14 into yearResults 15 select new 16 { 17 FirstName=r.FirstName, 18 LastName=r.LastName, 19 Wins=r.Wins, 20 Stars=r.Stars, 21 Results=yearResults 22 }); 23 foreach(var r in q) 24 { 25 Console.WriteLine("{0} {1}",r.FirstName,r.LastName); 26 foreach(var results in r.Results) 27 { 28 Console.WriteLine("{0} {1}.",results.Year,results.Position); 29 } 30 }
2.11 集合操作
1 var ferrariDrivers=from r in 2 Formula1.GetChampions() 3 from c in r.Cars 4 where c =="Ferrari" 5 orderby r.LastName 6 select r;
1 private static IEnumerable<Racer> GetRacersByCar(string car) 2 { 3 return from r in Formula1.GetChampions() 4 from c in r.Cars 5 where c==car 6 orderby r.LastName 7 select r; 8 }
1 Func<string , IEnumerable<Racer>> racersByCar= 2 car=>from r in Formula1.GetChampions() 3 from c in r.Cars 4 where c==car 5 orderby r.LastName 6 select r;
1 Console.WriteLine("World champion with Ferrari and McLaren"); 2 foreach(var racer in racersByCar("Ferraris").Interesect(racersByCar("McLaren"))) 3 { 4 Console.WirteLine(racer); 5 }
2.12 合并
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 racerNamesAndStarts=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 var racers=racerNames.Zip(racerNamesAndStarts,(first,second)=>first.Name+", starts: "+second.Starts); 17 foreach(var r in racers) 18 { 19 Console.WriteLine(r); 20 }
2.13 分区
1 int pageSize=5; 2 3 int numberPages=(int)Math.Ceiling(Formula1.GetChampions().Count()/(double)pageSize); 4 for(int page=0;page<numberPages;page++) 5 { 6 Console.WriteLine("Page {0}",page); 7 var racers=(from r in Formula1.GetChampions() 8 orderby r.LastName,r.FirstName 9 select r.FirstName+" "+r.LastName). 10 Skip(page*pageSize).Take(pageSize); 11 foreach(var name in racers) 12 { 13 Console.WriteLine(name); 14 } 15 Console.WriteLine(); 16 } 17
2.14 聚合操作符
1 var query=from r in Formula1.GetChampions() 2 let numberYears=r.Years.Count() 3 where numberYear>=3 4 orderby numberYears descending, r.LastName 5 select new 6 { 7 Name=r.FirstName+" "+r.LastName, 8 TimesChampion=numberYears 9 }; 10 foreach(var r in query) 11 { 12 Console.WriteLine("{0} {1}",r.Name,r.TimesChampion); 13 } 14
1 var countries=(from c in from r in Formula1.GetChampions() 2 group r by r.Country into c 3 select new 4 { 5 Country=c.Key, 6 Wins=(from r1 in c select r1.Wins).Sum() 7 } 8 orderby c.Wins descending, c.Country 9 select c).Take(5); 10 foreach(var country in countries) 11 { 12 Console.WriteLine("{0} {1}",country.Country,country.Wins); 13 }
2.15 转换操作符
1 List<Racer> racers=(from r in Formula1.GetChampions() 2 where r.Starts>150 3 orderby r.Starts descending 4 select r).ToList(); 5 foreach(var racer in racers) 6 { 7 Console.WriteLine("{0} {0:S}",racer); 8 }
1 var racers=(from r in Formula1.GetChampions() 2 from c in r.Cars 3 select new 4 { 5 Car=c, 6 Racer=r 7 }).ToLookup(cr=>cr.Car,cr=>cr.Racer); 8 if(racers.Contains("Williams")) 9 { 10 foreach(var williamsRacer in Racers["Williams"]) 11 { 12 Console.WriteLine(williamsRacer); 13 } 14 }
1 var list=new System.Collections.ArrayList(Formula1.GetChampions() as System.Collections.ICollection); 2 3 var query= from r in list.Cast<Racer>() 4 where r.Country=="USA" 5 orderby r.Wins descending 6 select r; 7 foreach(var racer in query) 8 { 9 Console.WriteLine("{0:A}",racer); 10 }
2.16 生成操作符
1 var values =Enumerable.Range(1,20); 2 foreach(var item in values) 3 { 4 Console.WriteLine("{0}",item); 5 } 6 Console.WriteLine(); 7 8 //结果 1 2 3 4 5 6 ...... 19 20
1 var values =Enumerable.Range(1,20).Select(n=>n*3);
C#基础:LINQ 查询函数整理