.Net学习——Linq常用拓展方法使用

本文主要演示Linq常用拓展方法。包括Where(),Single(),SingleOrDefault(),First(),
FirstOrDefault(),Count(),Any(),OrderBy(),Skip(),Take(),Max(),
Min(),Sum(),Average(),GroupBy(),Select(),ToList(),ToArray()。学会并掌握常用的Linq常用拓展方法,可以更快的处理数据源,其语法逻辑与SQL类似。

Linq语法常用于IEnumerable<泛型>这种可遍历的数据,如List<泛型> Array等。其底层逻辑就是遍历每一个元素,用一定的规则来判定元素是否符合标准。这个规则通常就是扩展方法中传入的委托参数。比如IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate); 该扩展方法用来筛选一定条件的数据,并返回新的可遍历的元素组。 委托变量predicate 对传入的TSource进行bool条件判断,如果符合规则,则将该元素加入到返回集中

委托变量通常指向一个用Lamda表达式描述的匿名方法,所以学习Linq之前还需对委托及Lamda表达式有一定的了解!
如果又不太了解的读友,可以参考我的前一篇文章 委托、委托与lamda表达式的关系

1 数据源

    public class Employee
    {
        public long Id;
        public string Name;
        public int Age;
        public int Salary;
        public int Gender;

        public Employee(long id, string name, int age, int salary, int gender)
        {
            Id = id;
            Name = name;
            Age = age;
            Salary = salary;
            Gender = gender;
        }

        public override string ToString()
        {            
            return $"Id:{Id},Name:{Name},Age:{Age},Salary:{Salary},Gender:{Gender}";
        }
    }
           List<Employee> list = new List<Employee>();
            list.Add(new Employee(1,"llk",28,4000,1));
            list.Add(new Employee(2, "lom", 28, 7000, 1));
            list.Add(new Employee(3, "lombok", 35, 9000, 0));

            list.Add(new Employee(4, "lld", 28, 8200, 0));
            list.Add(new Employee(5, "ssf", 25, 6000, 1));
            list.Add(new Employee(6, "ghj", 45, 12000, 0));



            list.Add(new Employee(7, "xxk", 28, 8200, 0));
            list.Add(new Employee(8, "qm", 25, 6000, 1));
            list.Add(new Employee(9, "fmh", 38, 9000, 0));

2 查询

2.1Where

IEnumerable Where(this IEnumerable source, Func<TSource, bool> predicate);
对source中的每个元素进行bool条件判断,为true时加入需要返回的集合中


           IEnumerable<Employee> items1 = list.Where(a=>a.Age>=35);
            Console.OutputEncoding = Encoding.Unicode;
            foreach (Employee employee in items1) {
                Console.WriteLine(employee.ToString());
            }

当前筛选条件为元素的Age必须不小于35

Id:3,Name:lombok,Age:35,Salary:9000,Gender:0
Id:6,Name:ghj,Age:45,Salary:12000,Gender:0
Id:9,Name:fmh,Age:38,Salary:9000,Gender:0

2.2 查询一条数据

1 TSource Single(this IEnumerable source, Func<TSource, bool> predicate);
当TSource满足bool条件判断时,返回一条数据。 0或多笔数据符合条件时,会报错
System.InvalidOperationException: 'Sequence contains more than one matching element'
System.InvalidOperationException: 'Sequence contains no matching element'

2 TSource SingleOrDefault(this IEnumerable source, Func<TSource, bool> predicate);
当TSource满足bool条件判断时,返回一条数据。 多笔数据符合条件时,会报错。不存在时会根据TSource的数据类型赋默认的值 比如 TSource为int时,不满足条件时SingleOrDefault查询的值将会是int的默认值 0
3 TSource First(this IEnumerable source, Func<TSource, bool> predicate);
当TSource满足bool条件判断时,返回一条数据。 0笔数据符合条件时,会报System.InvalidOperationException: 'Sequence contains no matching element'异常 多笔数据符合时,会选择最先符合条件的的一笔数据
4 TSource FirstOrDefault(this IEnumerable source, Func<TSource, bool> predicate);
当TSource满足bool条件判断时,返回一条数据。 0笔数据符合条件时,会根据TSource的数据类型赋默认的值 ,多笔数据符合时,会选择最先符合条件的一笔数据

            Employee emp = list.Single(i => i.Id == 1);
            Console.WriteLine(emp.ToString());

            emp = list.SingleOrDefault(i => i.Id == 0);
            Console.WriteLine(emp == null ? "Null" : emp.ToString());

            emp = list.First(i => i.Id>6);
            Console.WriteLine(emp.ToString());


            emp = list.FirstOrDefault(i => i.Gender == 0);
            Console.WriteLine(emp == null ? "Null" : emp.ToString());

Id:1,Name:llk,Age:28,Salary:4000,Gender:1
Null
Id:7,Name:xxk,Age:28,Salary:8200,Gender:0
Id:3,Name:lombok,Age:35,Salary:9000,Gender:0

3 计数Count

Count(this IEnumerable source, Func<TSource, bool> predicate);
对source中的每个元素进行bool条件判断,为true时计数

     int allCount = list.Count();
     int Fcount = list.Count(e => e.Gender == 1);
     int Mcount = list.Count(e => e.Gender == 0);
     Console.WriteLine($"员工总数为:{allCount} 男员工共{Mcount} 女员工共{Fcount}");

员工总数为:9 男员工共5 女员工共4

4 判断 Any

bool All(this IEnumerable source, Func<TSource, bool> predicate);
判断source中的元素是否至少有一个满足bool条件判断

   bool flag = list.Any(a => a.Salary > 15000);
   Console.WriteLine($"是否有员工的工资大于15000?{flag}"); //False
   flag = list.Any(a => a.Id==1);
   Console.WriteLine($"是否有员工的工号为1?{flag}"); //True

5 排序

IOrderedEnumerable OrderBy<TSource, TKey>(this IEnumerable source, Func<TSource, TKey> keySelector);
source元素根据给定的TKey来进行升序排
IOrderedEnumerable OrderByDescending<TSource, TKey>(this IEnumerable source, Func<TSource, TKey> keySelector);
source元素根据给定的TKey来进行降序排
IOrderedEnumerable ThenBy<TSource, TKey>(this IOrderedEnumerable source, Func<TSource, TKey> keySelector);
source元素根据给定的TKey来进行多规则升序排
IOrderedEnumerable ThenByDescending<TSource, TKey>(this IOrderedEnumerable source, Func<TSource, TKey> keySelector);
source元素根据给定的TKey来进行多规则降序排

  IEnumerable<Employee> newEmps = list.OrderBy(i => i.Age);
            Console.WriteLine("年龄升序排");
            foreach (Employee employee in newEmps)
            {
                Console.WriteLine(employee.ToString());
            }
            //source元素根据给定的TKey来进行降序排
            newEmps = list.OrderByDescending(i => i.Salary);
            Console.WriteLine("工资降序排");
            foreach (Employee employee in newEmps)
            {
                Console.WriteLine(employee.ToString());
            }

            //ThenBy 多规则排序
            newEmps = list.OrderByDescending(i => i.Salary).ThenBy(i => i.Age).ThenByDescending(i => i.Gender);
            Console.WriteLine("工资降序排再年龄升序排,性别降序排");
            foreach (Employee employee in newEmps)
            {
                Console.WriteLine(employee.ToString());
            }

年龄升序排
Id:5,Name:ssf,Age:25,Salary:6000,Gender:1
Id:8,Name:qm,Age:25,Salary:6000,Gender:1
Id:1,Name:llk,Age:28,Salary:4000,Gender:1
Id:2,Name:lom,Age:28,Salary:7000,Gender:1
Id:4,Name:lld,Age:28,Salary:8200,Gender:0
Id:7,Name:xxk,Age:28,Salary:8200,Gender:0
Id:3,Name:lombok,Age:35,Salary:9000,Gender:
Id:9,Name:fmh,Age:38,Salary:9000,Gender:0
Id:6,Name:ghj,Age:45,Salary:12000,Gender:0
工资降序排
Id:6,Name:ghj,Age:45,Salary:12000,Gender:0
Id:3,Name:lombok,Age:35,Salary:9000,Gender:
Id:9,Name:fmh,Age:38,Salary:9000,Gender:0
Id:4,Name:lld,Age:28,Salary:8200,Gender:0
Id:7,Name:xxk,Age:28,Salary:8200,Gender:0
Id:2,Name:lom,Age:28,Salary:7000,Gender:1
Id:5,Name:ssf,Age:25,Salary:6000,Gender:1
Id:8,Name:qm,Age:25,Salary:6000,Gender:1
Id:1,Name:llk,Age:28,Salary:4000,Gender:1
工资降序排再年龄升序排,性别降序排
Id:6,Name:ghj,Age:45,Salary:12000,Gender:0
Id:3,Name:lombok,Age:35,Salary:9000,Gender:
Id:9,Name:fmh,Age:38,Salary:9000,Gender:0
Id:4,Name:lld,Age:28,Salary:8200,Gender:0
Id:7,Name:xxk,Age:28,Salary:8200,Gender:0
Id:2,Name:lom,Age:28,Salary:7000,Gender:1
Id:5,Name:ssf,Age:25,Salary:6000,Gender:1
Id:8,Name:qm,Age:25,Salary:6000,Gender:1
Id:1,Name:llk,Age:28,Salary:4000,Gender:1

6 限制结果集 Skip和Take

Skip(n1) 跳过n1条数据,Take(n2) 获得n2条数据
通常可以用作数据的分页处理,Skip(3).Take(3); 每三条数据为一页,获得第二页的数据

 newEmps = list.OrderByDescending(i => i.Salary).Skip(3).Take(3);
            Console.WriteLine("分页显示");
            foreach (Employee employee in newEmps)
            {
                Console.WriteLine(employee.ToString());
            }

分页显示
Id:4,Name:lld,Age:28,Salary:8200,Gender:0
Id:7,Name:xxk,Age:28,Salary:8200,Gender:0
Id:2,Name:lom,Age:28,Salary:7000,Gender:1

7 聚合函数

            //TResult Max<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector);
            //Func<TSource, TResult> selector 对输入元素TSource判断最大值,返回泛型TResult
            int maxAge= list.Max(i=>i.Age);  // 获得最大年龄,Int类型
            string maxName = list.Max(i => i.Name); //获得最大名字,对String 进行比较

            Console.WriteLine("员工最大年龄" + maxAge);
            Console.WriteLine("员工最大名字" + maxName);

            //TResult Min<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector);
            // //Func<TSource, TResult> selector 对输入元素TSource判断最小值,返回泛型TResult
            int minAge = list.Min(i => i.Age);    // 获得最小年龄,Int类型
            Console.WriteLine("员工最小年龄" + minAge);

            //double Average<TSource>(this IEnumerable<TSource> source, Func<TSource, int> selector); 
            //System.Linq命名空间下基本上都是对IEnumerable接口的扩展方法,因此可以链式调用
            //查询Gender=0 女员工的平均工资
            double agvSalay = list.Where(i => i.Gender == 0).Average(i=>i.Salary);
            Console.WriteLine("女员工的平均工资" + agvSalay);

            //Gender=1 男性员工的工资大于6000的人数
            int qty = list.Where(i => i.Gender == 1 && i.Salary > 6000).Count();
            Console.WriteLine("男性员工的工资大于6000的人数" + qty);

员工最大年龄45
员工最大名字xxk
员工最小年龄25
女员工的平均工资9280
男性员工的工资大于6000的人数1

8 分组 GroupBy

 // IEnumerable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector);
            // Func<TSource, TKey> keySelector 按照TKey 进行分组
            // IGrouping<TKey, TSource> 返回以Tkey为组的TSource集合 TSource的类型与source的类型一致
            IEnumerable<IGrouping<int, Employee>> sources= list.GroupBy(i => i.Age);
            foreach (IGrouping<int, Employee> group in sources) {
                Console.WriteLine("年龄组为:" + group.Key);
                foreach (Employee employee in group)
                {
                    Console.WriteLine(employee.ToString());
                }
                Console.WriteLine("最大工资"+group.Max(i=>i.Salary));
            }

年龄组为:28
Id:1,Name:llk,Age:28,Salary:4000,Gender:1
Id:2,Name:lom,Age:28,Salary:7000,Gender:1
Id:4,Name:lld,Age:28,Salary:8200,Gender:0
Id:7,Name:xxk,Age:28,Salary:8200,Gender:0
最大工资8200
年龄组为:35
Id:3,Name:lombok,Age:35,Salary:9000,Gender:0
最大工资9000
年龄组为:25
Id:5,Name:ssf,Age:25,Salary:6000,Gender:1
Id:8,Name:qm,Age:25,Salary:6000,Gender:1
最大工资6000
年龄组为:45
Id:6,Name:ghj,Age:45,Salary:12000,Gender:0
最大工资12000
年龄组为:38
Id:9,Name:fmh,Age:38,Salary:9000,Gender:0
最大工资9000

9 投影 Select

Enumerable Select<TSource, TResult>(this IEnumerable source, Func<TSource, TResult> selector);
Func<TSource, TResult> selector 將TSource转换成另一个类型

         var ages =  list.Select(i=>i.Age);
            Console.WriteLine("遍历所有的年龄");
            foreach (int age in ages)
            {
                Console.WriteLine(age);
            }
            //Employee to String
            var genders = list.Select(i=>i.Gender==1?"男":"女");
            Console.WriteLine("遍历所有的性別");
            foreach (string gender in genders)
            {
                Console.WriteLine(gender);
            }

遍历所有的年龄
28
28
35
28
25
45
28
25
38
遍历所有的性別








10 集合转换 ToList和ToArray

在一定的情形下,需要将IEnumerable 通过ToList转换为List类型 ToArray转换为数组类型

  List <Employee> li = list.ToList();
            Employee[] arr= list.ToArray();
            foreach (Employee e in li)
            {
                Console.WriteLine(e.ToString());
            }

            foreach (Employee e in arr)
            {
                Console.WriteLine(e.ToString());
            }

11 链式调用

System.Linq命名空间下的扩展方法基本上都是对IEnumerable<泛型>的处理,且Where、Select、OrderBy、GroupBy、Take、Skip的返回值都是IEnumerable <泛型>,所有可以进行链式调用去更快速的处理数据

  //分组 投影 聚合函数
   var obj=   list.GroupBy(i=>i.Gender).Select(g=>new {Gender=g.Key==1?"男":"女",Count=g.Count(),MaxSalary=g.Max(item=>item.Salary),AgvSalay=g.Average(item=>item.Salary)});
   foreach(var o in obj)
   {
        Console.WriteLine($"Gender:{o.Gender},MaxSalary:{o.MaxSalary} AgvSalay:{o.AgvSalay}");
   }

Gender:男,MaxSalary:7000 AgvSalay:5750
Gender:女,MaxSalary:12000 AgvSalay:9280

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值