C#笔记 -- LINQ方法

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)
                });

posted on 2023-10-01 00:12  老菜农  阅读(12)  评论(0编辑  收藏  举报

导航