LINQ的简单查询
查询
假设有一个自定义类Kongfu:
class Kongfu { public int KongfuId; public string KongfuName; public int Power; public Kongfu() { } }
Main中实例了一个Kongfu类列表:
var kongfu = new List<Kongfu> { new Kongfu {KongfuId = 1, KongfuName = "打狗棒法", Power = 90}, new Kongfu {KongfuId = 2, KongfuName = "降龙十八掌", Power = 95}, new Kongfu {KongfuId = 3, KongfuName = "葵花宝典", Power = 100} };
如果我们要过滤列表中Power>90的元素,一般情况下使用for和foreach过于麻烦,此时我们可以使用LINQ做查询和返回
Main中:
var res = from k in kongfu where k.Power>90 //判断 select k; //返回k至res中,此时k是Kongfu类,所以res也是一个Kongfu的列表 foreach(var temp in res) { Console.WriteLine(temp); //需要重写Kongfu类的ToString()方法 } Console.ReadKey();
当有多个条件需要判断时可用&&隔开,比如
where k.Power>90 && k.KongfuName == ”降龙十八掌”
查询的关键字
以下部分来自博客:https://blog.csdn.net/IT_choshim/article/details/83658748
From:子句被查询的数据源(相当于for循环),多个from表示从多个数据源查询数据(c#会把符合from字句的查询表达式转换为SelectMany()扩展方法)
Where:子句指定元素所满足的过滤条件(相当于if判断),多个Where字句则表示了并列条件,必须全部满足才能入选,每个字句可以使用&& ||连接多个表达式
orderby、descending:表现方式(相当于排序方式,升序、降序。。。)
Select:指定查询要返回的目标数据(相当于return),可以指定任何类型,甚至是匿名类型
使用select创建新数组(select new{成员1,成员2,.....};)时一般我们会加上成员名如:
select new{_count=k.Count(),_name=k.Name};//输出 _count=.......,_name=.......
但也可以不加成员名,此时有两种情况。
第一种:
select new{k.Count(),k,Name};//k.Count()编译不通过,即方法不能作为变量名直接使用
第二种:
select new{k.Age,k,Name};//输出 Age=.....,Name=...... 则会输出原本的变量名
into:提供一个临时的标识符,可以引用join、group和select字句的结果。
(1)直接出现在join字句之后的into关键字会被翻译为Groupjoin(into之前的变量可以继续使用)
(2)select或group字句之后的into会重新开始一个查询,让我们可以继续引入Where,orderby和select字句,它是对分布构建查询表达式的一种简写方式(into之前的查询变量都不可以再使用)
var intoLinq = from num in peoList group num by num.city into groupnum
以上示例:into 字面解释意为“打入”,以上事例将遍历proList得到的num筛选出city属性放入groupnum中,这里的groupnam可以看作是一个集合,这个集合存的是city属性
let:引入用于存储查询表达式结果的范围变量,通常能达到层次感会更好,使代码更易于阅读
string[] strings = { "hello world.", "lin qing xia", "wang zu xian" }; var strs = from s in strings let words = s.Split(‘ ‘) from word in words let w = word.ToUpper() select w; foreach(var s in strs) { Console.WriteLine(s); }
将遍历的元素进行处理,并将处理结果存放到words,这里的words也可看作一个集合
联合查询
联合查询可以同时查询多个对象。而且查询时每个对象会将元素一一匹配。比如列表对象1中有4个元素,列表对象2中有5个元素,则会匹配4*5=20次,所以在添加到结果时要慎重,过滤逻辑要写清楚,否则容易重复添加。
以上面的Kongfu和新自定义类MartialArtsMaster类为例:
class MartialArtsMaster { public int Id { get; set; } public string Name { get; set; } public int Age { get; set; } public string Menpai { get; set; } public string Kungfu { get; set; } public int Level { get; set; } }
假设我们实例好了一个MartialArtsMaster数组,命名为masterList
//Linq联合查询 var res = from k in kongfu from m in masterList where k.KongfuName == m.Kungfu && k.Power>90
select m;//①
然后用foreach遍历res输出即可
如若我们要同时返回满足条件的两个数组中的元素,则可以创建一个新的临时对象,将①改为:
select new { _master = m , _kungfu=k };//②
这样res中就能同时插入Kongfu类和MartialArtsMaster类中满足条件的元素了
扩展方法写法
查询
扩展方法都是调用List中的方法,不同于以上LINQ表达式的查询,我们还有一种方法可以过滤元素:
同样是Kongfu类和kongfu列表:
①var res = kongfu.Where(Method1); //使用Where(),参数需要传入一个方法,返回值为bool,如果为true,将元素添加到到res中;否则过滤掉 foreach(var temp in res) { Console.WriteLine(temp); //需要重写Kongfu类的ToString()方法 } //过滤方法 ②static bool Method1(Kongfu kongfu) { if(kongfu.Power>90) return true; return false; }
注意Where()是传入一个方法。
再简便点可以直接不写方法,引入Lambda表达式将①改为:
③var res = kongfu.Where(k=>k.Power>90);
这样的话②都不用写。
当有多个参数时③可写成:
④var res = kongfu.Where(k=>k.Power>90 && k.KongfuName==”降龙十八掌”);
联合查询
LINQ中的联合查询可以写成这种形式:
//扩展方法的联合查询 var res = masterList.SelectMany(m => kongfu, (m, k) => new {_master = m, _konfu = k}) .Where(x => x._master.Kungfu == x._konfu.KongfuName && x._konfu.Power > 90);
官方释义:将序列的每个元素投影到 IEnumerable<TCollection>,并将结果序列合并为一个序列,并对其中每个元素调用结果选择器函数。
这个用法,可以对已合成一个大集合的每个元素调用结果选择器,返回自己想要的集合类型。
第一个参数:m=>kongfu
m指定是想要处理的每个masterList对象,而kongfu则是想让m实例映射的kongfu集合;
第二个参数:(m, k) => new { _master= m, _kongfu = k }
m与k分别指定是映射后(其实有点类似数据库的CROSS JOIN)的MartialArtsMaster实例与Kungfu实例,如名为M1的MartialArtsMaster类,其kongfu名为k1,那么m与k就是:M1/k1(指定是名称),处理其他MartialArtsMaster类也是如此。而new { _master= m, _kongfu = k }则是返回的一个由自己定义的匿名类型。
实际上SelectMany对应的LINQ语句为:
var res = from m in masterList from k in kongfu select new{ masterList.kungfu == kongfu && kongfu.Power > 90 };
SelectMany()用来指定集合,Where用来查询并返回所需元素的,两者结合即可起到运算或筛选的效果。
里面包含了大量的委托和Lambda表达式的使用,一开始不懂可以理解,之后遇到再深入学习
SelectMany()具体可以查看博客:https://www.cnblogs.com/cncc/p/9840463.html,内有详细解析
对结果进行排序
使用OrderBy()进行排序
依然是武林高手MartialArtsMaster类的例子:
var res = mastersList.Where(m=>m.Menpai=="华山").OrderBy(m=>m.Age);//根据年龄,默认从小到大
如果需要从大到小的排序,则使用OrderByDescending();
若需要排序后再排序,则在OrderBy()或OrderByDescending()后面加上ThenBy()或ThenByDescending();
集合联合
集合联合使用join … in … on … equals … 的形式,实现集合的多条件连接,有点类似于SelectMany()
依然以masterList和kongfu对象为例:
var res = from m in masterList join k in kongfu on m.Kungfu equals k.KongfuName //将kongfu联合masterList,筛选出其中功夫名相同的对象 Where k.Power>90 select new{_master=m,_kongfu =k };
分组查询
使用 into进行分组
以武林高手和武功对象为例,输出所有武功的信息和修炼武功的高手的数量:
var res = from k in kongfu join m in MasterList on k.KongfuName equals m.Kungfu into groups OrderBy groups.Count()//按照数量排序 select new {_kungfu=k,_count=groups.Count()};
按照自身字段分组 group
使用group by对自身分组
比如,我们要将master中的成员按照武学分组,并输出修炼该武学的人数和武学名
var res = from m in masterList group g by m.kongfu into g select new{g.Count(),g.Key};//输出人数,武学名
关于g.Key:Key表示分组根据的属性
量词操作符 any all 判断集合中是否符合某个条件
使用List<T>.All(判断条件)可以判断集合内的所有元素是否符合条件,返回值为bool
使用List<T>.Any(判断条件)可以判断集合内的元素是否有一个符合条件,返回值为bool
例如:
bool res1 = masterList.Any(m => m.Menpai == "丐帮");//判断组内是否有一个元素满足条件 Console.WriteLine(res1);//true res1 = masterList.All(m => m.Menpai == "丐帮");//判断组内是否全部元素都满足条件 Console.WriteLine(res1);//false