一、
LINQ中提供了大量类似Where的扩展方法,简化数据处理。大部分都在System.Linq命名空间中
基本是对于lEnumerable 接口的扩展方法。
数组、List、Dictionary、Set... 都是实现了 lEnumerable 接口。因此都是可以使用这些扩展方法。
准备初始数据
csharp
class Employee
{
public long ld { get; set; }
public string Name {get; set; }//姓名
public int Age {get; set; }//年龄
public bool Gender {get; set; }//性别
public int Salary{get; set; }//月薪
public override string ToString()
{
return
$"ld={ld},Name={Name},Age={Age},Gender={Gender},Salary={Salary}";
}
}
csharp
List<Employee> list = new List<Employee>;
list.Add(new Employee {ld = 1, Name = "jerry", Age = 28, Gender = true, Salary = 5000 });
list.Add(new Employee {ld = 2, Name = "jim", Age = 33, Gender = true, Salary = 3000 });
list.Add(new Employee { ld = 3, Name = "lily", Age = 35, Gender = false, Salary = 9000 });
list.Add(new Employee {ld =4, Name ="lucy",Age = 16, Gender = false, Salary= 2000 });
list.Add(new Employee {ld=5,Name = "kimi",Age = 25,Gender = true, Salary = 1000 });
list.Add(new Employee {ld =6, Name = "nancy", Age = 35, Gender = false, Salary = 8000 });
list.Add(new Employee {ld=7,Name = "zack", Age = 35, Gender = true, Salary = 8500 });
list.Add(new Employee {ld = 8, Name = "jack", Age = 33, Gender = true, Salary = 8000 });
where 方法
Where方法:每一项数据都会经过predicate的测试,如果针对一个元素,predicate执行的返回值为true,那么这个元素就会放到返回值中。
Where参数是一个lambda表达式格式的匿名方法,方法的参数e表示当前判断的元素对象。参数的名字不一定非要叫e,不过一般lambda表达式中的变量名长度都不长。
传入一个过滤的lambda 表达式
source对哪个数据做过率,predicate 泛型委托(Tsource是传入数据类型,返回值是bool。判断参数是否满足过滤条件)
示例:
过滤年龄大于三十
运行结果
Count()方法
:获取数据条数
int count1 = list.Count(e =>e.Salary>5000 || e.Age < 30);
int count2 = list.Where(e =>e.Salary> 5000 || e.Age <30).Count();
源码:
示例:
运行结果
Any()方法
:是否至少有一条数据满足条件
bool b1 = list.Any(e => e.Salary >8000);
bool b2 = list.Where(e =>e.Salary>8000).Any();
有可能比Count()实现效率高。any()获取到一条满足条件的数据就不会继续往下寻找。count需要查找所有满足条件的数据。
示例
获取一条数据(是否带参数的两种写法)
Single:有且只有一条满足要求的数据;
多条、一条满足条件的数据都没有,会抛出异常
示例:
运行结果:报错,这么序列中,含有多于一条数据。
示例2:取出只有一个满足条件的数据
运行结果
示例3: 没有匹配结果,和直接在single中传入条件
运行结果:报错,没有匹配的元素
SingleOrDefault :最多只有一条满足要求的数据;
多条满足条件数据,会抛出异常。没有则返回默认值(int 0,string null)
示例1:有一条数据满足条件
运行结果
示例2:一条满足条件的数据都没有的情况,返回默认值
运行结果
First :至少有一条,返回第一条;
多条返回第一条,一条没有会抛出异常
示例1:多条返回第一条
运行结果:
示例2:一个都没有的情况
运行结果:抛出异常
FirstOrDefault :返回第一条或者默认值
返回一条,一条都没有就返回默认值
选择合适的方法,"防御性编程"
排序:
Order()对数据正序排序;
list.OrderBy(e => e.Age);
示例:根据age 排序
运行结果:
OrderByDescending()倒序排序;
示例:
运行结果
对于简单类型排序
示例:根据自己排序
运行结果:
特殊案例: 按照最后一个字符排序;
运行结果:
用Guid或者随机数进行随机排序。
多规则排序
可以在Order()、OrderByDescending()后继续写ThenBy()、ThenByDescending().
案例:优先按照Age排序,如果Age相同再按照Salary排序
csharp
list.OrderBy(e =>e.Age).ThenByDescending(e>e.Salary)
千万不要写成
list.OrderBy(e => e.Age).OrderByDescending(e =>e.Salary)
示例
运行结果
连续使用两次orderby,导致排序混乱
限制结果集,获取部分数据
:Skip(n)跳过n条数据,Take(n)获取n条数据。
案例:获取从第2条开始获取3条数据var orderedltems1 = list.Skip(2).Take(3)
Skip()、Take()也可以单独使用。
示例
运行结果:
聚合函数
:Max()、Min()、Average()、sum()、Count ().
LINQ中所有的扩展方法几乎都是针对IEnumerable接口的,而几乎所有能返回集合的都返回lEnumerable,所以是可以把几乎所有方法"链式使用"的。list.Where(e =>e.Age > 30).Min(e=>e.Salary)
示例:
年龄大于30,平均工资
分组:
GroupBy()方法参数是分组条件表达式,返回值为lGrouping<TKey,Tsource>类型的泛型IEnumerable,也就是每一组以一个IGrouping对象的形式返回。
lGrouping是一个继承自lEnumerable的接口,IGrouping中Key属性表示这一组的分组数据的值。
根据年龄分组
运行结果
例子:根据年龄分组,获取每组人数、最高工资、平均工资。用var简化编程。
运行结果
投影
把集合中的每一项转换为另外一种类型
csharp
lEnumerable<int> ages = list.Select(e =>e.Age);
lEnumerable<string> names =list.Select(e=>e.Gender?"男":"女");
var dogs = list.Select(p=>newDog{NickName=e.Name,Age=e.Age});
示例:
运行结果
匿名类型:
var p = new {Name="tom",ld=1}
var p1 = new {name,ld=1,p.Age};
编译时,创建了一个匿名类型
通过反编译看匿名类型原理。
匿名类型,是编译器为我们生成的类型
var的高光时刻!
投影与匿名类型:
csharp
var items= list.Select(e=>new{e.Name,e.Age,XingBie=e.Gender?"男":'女"});
var items = list.GroupBy(e =>e.Gender)
.Select(g=>new{
Gender=g.Key,
Count=g.Count(),
AvgSalary=g.Average(e => e.Salary),
MinAge= g.Min(e =>e.Age)
}
);
集合转换
:有一些地方需要数组类型或者List类型的变量,我们可以用ToArray()方法和ToList()分别把IEnumerable转换为数组类型和List类型
示例
链式调用
Where、Select、OrderBy、 GroupBy、Take、skip等返回值都是lEnumerable类型,所以可以链式调用。
例子:"获取ld>2的数据,然后按照Age分组,并且把分组按照Age排序然后取出前3条,最后再投影取得年龄人数、平均工资
查询语法
使用Where、OrderBy、Select等 扩展方法进行数据查询的写法叫做"LINQ方法语法"。
还有一种"查询语法"的写法。
csharp
var items2 = from e in list
where e.Salary>3000 orderby e.Age
select new {e.Name,e.Age, Gender =e.Gender?"男":"女"};