C#笔记 -- LINQ方法
public class Emp
{
public string Id { get; set; }
public int Age { get; set; }
public string Name { get; set; }
public double Salary { get; set; }
public bool Gender { get; set; }
}
List<Emp> empList = new List<Emp>
{
new Emp { Id= "1", Age = 1, Name = "mark" , Salary = 111.0, Gender = true},
new Emp { Id= "2", Age = 1, Name = "amy", Salary = 111.0, Gender = false},
new Emp { Id= "3", Age = 2, Name = "bob", Salary = 112.0, Gender = true}
};
一、委托
-
委托是可以指向方法的类型, 调用委托变量时执行的就是变量指向的方法
-
.net定义了泛型委托
Action
(无返回值)、Func
(有返回值), 所以一般不用自定义委托类型
Action<in T1, ..., in T16> action;//0~16个入参, 无返回值
Func<in t1, ..., in T16, out TResult>func; //0~16个入参, 返回值TResult
二、匿名方法
-
以
delegate
声明的方法
Action<in T1, ..., in T16> action = delegate(T1 t1, ..., T16 t16)
{
//操作
};
Func<in T1, ..., in T16, out TResult> action = delegate(T1 t1, ..., T16 t16)
{
//操作
return tResult;
};
-
可以采用
lambda
表达式简化
Action<in T1, ..., in T16> action = (t1, ..., t16) =>
{
//操作
};
Func<in T1, ..., in T16, out TResult> action = (t1, ..., t16) =>
{
//操作
return tResult;
};
三、LINQ常用扩展方法
1、IEnumerable<T> Where(predicate)
-
predicate返回true, 这个元素就会放到返回值中
-
predicate可以匿名委托写, 也可以用Lambda表达式
List<int> beforeList = new List<int> { 1, 2, 3 };
IEnumerable<int> enumerable = beforeList.Where(e => e > 2);
2、int Count(predicate)
-
返回满足predicate的元素个数
List<int> beforeList = new List<int> { 1, 2, 3 };
int count = beforeList.Count(e => e > 2);
3、bool Any(predicate)
-
返回是否至少有一个满足predicate的元素
List<int> beforeList = new List<int> { 1, 2, 3 };
bool hasAny = beforeList.Any(e => e > 2);
4、获取一条数据
(1)T Single(predicate)
-
获取有且只有一条满足要求的数据
-
没获取到就报错
-
有多条就报错
(2)T SingleOrDefault(predicate)
-
获取有且只有一条满足要求的数据
-
没获取到就返回
T
类型的默认值 -
有多条就报错
(3)T First(predicate)
-
获取第一条满足要求的数据
-
没获取到就报错
(4)T FirstOrDefault(prediate)
-
获取第一条满足要求的数据
-
没获取到就返回
T
类型的默认值
5、排序
(1)IEnumerable<T> OrderBy([选填]排序依据)
正序
(2)IEnumerable<T> OrderByDescending([选填]排序依据)
倒序
(3)排序特殊案例
A.按照属性最后一个字符排序
public class T
{
public string StrProp { get; set; }
}
IEnumberable<T> list2 = list.OrderBy(e => e.StrProp[e.StrProp.Length-1]);
B.用Guid
或者随机数进行随机排序
IEnumerable<T> list2 = list.OrderBy(e => Guid.NewGuid());
(4)多排序规则ThenBy(排序依据)
、ThenByEdscending(排序依据)
-
可以在
Order()
、OrderByDescending()
后继续写ThenBy()
、ThenByDescending()
例子: 优先按照Age正序, 如果Age相同再按照Salary倒序
empList
.OrderyBy(e => e.Age)
.ThenByDescending(e => e.Salary);
6、限制结果集
(1)IEnumerable<T> Skip(n)
跳过n条数据
(2)IEnumerable<T> Take(n)
获取n条数据
案例: 从第2条开始获取3条数据
list.Skip(2).Take(3);
四、聚合函数
函数 | 描述 |
---|---|
Max() |
求最大 |
Min() |
求最小 |
Average() |
求平均 |
Sum() |
求和 |
Count() |
求个数 |
1、IGrouping<TKey, TSource> GroupBy(分组字段值)
分组函数
-
GroupBy()
可以和聚合函数一起用, 表示分组的聚合 -
IGrouing
-
继承自
IEnumerable
-
Key
属性表示这一组的分组数据的字段值
-
-
使用分组函数后, 后面的链式操作, 全部变为对组操作, 而不是对元素
-
后面对于组的操作, 可以从组中再获取元素, 比如使用投影
empList.Where(e => "2".CompareTo(e.Id) < 0)
.GroupBy(e => e.Age)
//分完了组, 此刻开始只能对组操作
.OrderBy(g => g.Key)
.Take(3)
//Select拆组, 对元素操作
.Select(g => new
{
Age = g.Key,
Total = g.Count(),
AvgSalary = g.Average(e => e.Salary)
});
例子: 查询每一组年薪最高
//分组
IEnumerable<IGrouping<int, Emp>> empGroupByAge = empList.GroupBy(e => e.Age);
//遍历每个组
foreach (IGrouping<int, Emp> group in empGroupByAge)
{
//求每个组米最多
double highestSalary = group.Max(e => e.Salary);
//Key就是Age, 分组条件就是年龄
Console.WriteLine($"{group.Key}组, 钱最多的¥{highestSalary}");
//遍历当前组, 获取当前组中的每一个Emp
foreach (Emp emp in group)
{
Console.WriteLine($"年龄: {emp.Age}, 名字: {emp.Name}");
}
Console.WriteLine("--------------------");
}
例子: 查询每一组年薪最高的人
//<分组的键的值, 每组钱最多的人集合>
Dictionary<int, List<Emp>> mostRichEmpDic = new Dictionary<int, List<Emp>>();
foreach (var g in empList.GroupBy(e => e.Age))
{
double maxSalary = g.Max(e => e.Salary);
//每组钱最多的人集合
IEnumerable<Emp> mostRichEmps = g.Where(e => e.Salary == maxSalary);
mostRichEmpDic[mostRichEmps.First().Age] = mostRichEmps.ToList();
}
五、投影
1、IEnumberable<TResult> Select(转换方式)
-
把集合中的每一项转换为另一种类型
//把集合中的每一项转换为int
IEnumberable<int> ages = list.Select(e => e.Age);
//把集合中的每一项转换为性别
IEnumerable<string> empGenders = empList.Select(e => e.Gender ? "male" : "female");
//转换人员集合为人类匿名集合
var personList = empList.Select(e => new { e.Name, Gender = e.Gender ? "男" : "女" });
-
根据分组结果生成集合
//根据年龄生成最高和最低薪资的集合
empList.GroupBy(e => e.Age).Select(g => new
{
AgeArea = g.Key,
MaxSalary = g.Max(e => e.Salary),
MinSalary = g.Min(e => e.Salary),
AreaTotal = g.Count()
});
-
根据年龄分组, 并投影最低和最高薪资的人的匿名集合
empList.GroupBy(e => e.Age).Select(g => new
{
AgeArea = g.Key,
MaxSalary = g.Max(e => e.Salary),
MaxEmps = g.Where(e => e.Salary == g.Max(e => e.Salary)),
MinSalary = g.Min(e => e.Salary),
MinEmps = g.Where(e => e.Salary == g.Min(e => e.Salary)),
AreaTotal = g.Count()
});
六、集合转换
-
需要使用数组或者列表类型的变量
1、T[] IEnumerable<T>.ToArray()
Emp[] emps = empList.Where(e => "bob".Equals(e.Name)).ToArray();
2、List<T> IEnumerable<T>.ToArray()
List<Emp> empAfterList = empList.Where(e => "bob" == e.Name).ToList();
七、链式调用
-
Where()
、Select()
、OrderBy()
、GroupBy()
等返回值都是或者继承IEnumerable<T>
类型, 所以可以链式调用
例子: 获取ID>2的数据, 然后按照Age分组, 并且把分组按照Age排序, 取出前3条, 最后再投影取得年龄、人数、平均工资
empList.Where(e => "2".CompareTo(e.Id) < 0)
.GroupBy(e => e.Age)
.OrderBy(g => g.Key)
.Take(3)
.Select(g => new
{
Age = g.Key,
Total = g.Count(),
AvgSalary = g.Average(e => e.Salary)
});