C# Linq和lambda的详细使用

Linq声明式语法

1.找出C盘中5个最大的文件。

 var query = from file in new DirectoryInfo(path).GetFiles()
                        orderby file.Length descending
                        select file;
            foreach (var file in query.Take(5))
            {
                Console.WriteLine($"{file.Name,-20}:{file.Length,10:N}");
            }

query白话:from表示重哪里来,from file 就表示file从哪里来,in表示在…里面。in 集合,表示在这个集合里面。from file in new DirectoryInfo(path).GetFiles()连起来就是fileDirectoryInfo(path).GetFiles()里面拿出来,然后对每个file做排序操作。

Linq命令式语法

 var query = new DirectoryInfo(path).GetFiles().OrderByDescending(f=>f.Length).Take(5);
            foreach (var file in query)
            {
                Console.WriteLine($"{file.Name,-20}:{file.Length,10:N}");
            }

lambda演算

假如我们要筛选名字为A开通的客户,原始写法。
在这里插入图片描述
这种写法每次都需要定义方法,很痛苦。其中WhereLinq的命令式语法,会遍历集合中的所有数据,True保留在集合False则不保留。

于是有了匿名方法。
在这里插入图片描述
这种写法看起来还是很复杂,而且delegate这种关键字并不参与代码的逻辑,类型string本身就是集合类型也可以省略,只有一行代码也没必要要返回值。于是就有了lambda

去掉上面该去掉的就是Lambda写法。
在这里插入图片描述

把上面的 题目改一下,找出C盘中5个最大的文件,并且返回以小写b开头的文件。

 var query = new DirectoryInfo(path).GetFiles()
                .OrderByDescending(f=>f.Length)
                .Where(f=>f.Name.StartsWith("b"))
                .Take(5);
            foreach (var file in query)
            {
                Console.WriteLine($"{file.Name,-20}:{file.Length,10:N}");
            }

结构化查询

找出C盘中5个最大的文件,并且返回以小写b开头的文件,并且文件大小大于4000

 var query = from file in new DirectoryInfo(path).GetFiles()
                        where file.Name.StartsWith("b") && file.Length > 4000
                        orderby file.Name
                        select file;
            foreach (var file in query)
            {
                Console.WriteLine($"{file.Name,-20}:{file.Length,10:N}");
            }

select为最后需要返回的结果导向。比如sql中的 select * 就返回所有字段这里的 file也表示返回所有。
在这里插入图片描述
这里的query返回类型,完全有select决定,如果返回file.Name则是string类型。
在这里插入图片描述
命令式写法:

   var query = new DirectoryInfo(path).GetFiles()
                .Where(f => f.Name.StartsWith("b") && f.Length > 4000)
                .OrderBy(f => f.Name);
            foreach (var file in query)
            {
                Console.WriteLine($"{file.Name,-20}:{file.Length,10:N}");
            }

Linq原理解析

where语句实现一个扩展方法。
新建一个类MyLinq实现MyWhere方法。

using System;
using System.Collections;
using System.Collections.Generic;

namespace Linq
{
    public static class MyLinq 
    {
        public static IEnumerable<T> MyWhere<T>(
            this IEnumerable<T> source , Func<T,bool> predicate
            ) 
        {
            var rusult = new List<T>();
            foreach (var item in source)
            {
                if (predicate(item)) 
                {
                    rusult.Add(item);
                }
            }

            return rusult;
        }
    }
}

this IEnumerable<T> source表示当前集合元数据。
该方法实现了和where一样的效率。
我们可以运行一下我们自己的扩展方法MyWhere

 var query = new DirectoryInfo(path).GetFiles()
                .MyWhere(f => f.Name.StartsWith("b") && f.Length > 4000)
                .OrderBy(f => f.Name);

效果也可以出来,但是原生的where语句支持懒加载。懒加载的底层就是用了 yield return通过 yield return返回一个集合迭代,最终实现懒加载,不懂yield return的请查看我的 yield return文章。
MyWhere改动后如下:

using System;
using System.Collections;
using System.Collections.Generic;

namespace Linq
{
    public static class MyLinq 
    {
        public static IEnumerable<T> MyWhere<T>(
            this IEnumerable<T> source , Func<T,bool> predicate
            ) 
        {
       
            foreach (var item in source)
            {
                if (predicate(item)) 
                {
                    yield return item;
                }
            }

        
        }
    }
}

案例:读取文本中的汽车数据并打印出来。
在这里插入图片描述

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace LinqTest
{
    class Program
    {
        static void Main(string[] args)
        {
            List<Car> cars = ProcessCars("Cars.txt");
            foreach (var car in cars)
            {
                Console.WriteLine($"型号:{car.CarNumber ,-20}品牌:{car.CarName,-20}最大马力:{car.MaxML,-10}油耗:{car.FCPHK,-10}");
            }
            Console.Read();
        }

        private static List<Car> ProcessCars(string path)
        {
            //Skip 跳过第一行
            var result = File.ReadAllLines(path)
                .Skip(1)
                .Where(r => r.Length > 1)
                .Select(line => {
                    var columns = line.Split(",");
                    Car car = new Car
                    {
                        CarNumber = columns[0],
                        CarName = columns[1],
                        MaxML = columns[2],
                        FCPHK = columns[3]
                    };
                    return car;


                });

            return result.ToList();
            
        }
    }
}

排序与过滤

查找油耗小于15的宝马汽车,并根据百公里油耗和最大马力排序。并取出符合要求的一辆汽车。
命令式:

 var query = cars
                .Where(c=>c.CarName.Equals("宝马")&& int.Parse(c.FCPHK) <= 15)
                .OrderByDescending(c => c.FCPHK)
                .ThenByDescending(c => c.MaxML)
                .FirstOrDefault();

其中ThenByDescending为二级排序。
声明式:

 var query = (from car in cars
                         where car.CarName == "宝马" && int.Parse(car.FCPHK) <= 15
                         orderby car.FCPHK descending, car.MaxML descending
                         select car).FirstOrDefault();

查询操作

 //查询 是否有大众汽车
            var query1 = cars.Any(c => c.CarName == "大众");
            if (query1) 
            {
                Console.WriteLine("包含!");
            }

            //判断集合是否为空
            var isCarsEmpty = cars.Any();
            if (!isCarsEmpty) 
            {
                Console.WriteLine("不是空集合");
            }

            //查询集合中是否包含有该对象
            cars.Contains(query);

            //查询集合是否都是大众汽车 
            cars.All(c => c.CarName == "大众");

数据投影与SelectMany

ToCar是迭代器的扩展方法,通过扩展方法可以直接把字符串集合返回为对象集合。

  public static class CarExtension 
    {
        public static IEnumerable<Car> ToCar(this IEnumerable<string> source)
        {

            foreach (var line in source)
            {
                var columns = line.Split(",");
                yield return new Car
                {
                    CarNumber = columns[0],
                    CarName = columns[1],
                    MaxML = columns[2],
                    FCPHK = columns[3]
                };

            }
        }
    }
}

调用ToCar方法。

  var result = File.ReadAllLines(path)
                .Skip(1)
                .Where(r => r.Length > 1)
                .ToCar();

如果不想返回整个对象,想进行字段筛选过滤。可以采用new{}(匿名对象的形式,过滤数据。)

 var query = (from car in cars
                         where car.CarName == "宝马" && int.Parse(car.FCPHK) <= 15
                         orderby car.FCPHK descending, car.MaxML descending
                         select new {
                                      CarName = car.CarName,
                                      CarNumber =car.CarNumber,
                                      MaxML=car.MaxML,
                                      FCPHK=car.FCPHK
                         }).FirstOrDefault();

            Console.WriteLine($"型号:{query.CarNumber,-20}品牌:{query.CarName,-20}最大马力:{query.MaxML,-10}油耗:{query.FCPHK,-10}");

数据连接Join

声明式

 var query = (from car in cars
                         join  manufacturer in manufacturers on car.CarName equals manufacturer.CarName
                         orderby car.FCPHK descending, car.MaxML descending
                         select new
                         {
                             CarName = car.CarName,
                             CarNumber = car.CarNumber,
                             MaxML = car.MaxML,
                             FCPHK = car.FCPHK,
                             Addrse= manufacturer.CarAddres
                         }).FirstOrDefault();

命令式

 var query2 = cars.Join(manufacturers, (c) => c.CarName, (m) => m.CarName, (c, m) => new
            {
                Car = c,
                Manufacturer = m
            }).OrderByDescending(JoinDate => JoinDate.Car.FCPHK)
            .Select(JoinDate=> new {
                CarName = JoinDate.Car.CarName,
                CarNumber = JoinDate.Car.CarNumber,
                MaxML = JoinDate.Car.MaxML,
                FCPHK = JoinDate.Car.FCPHK,
                Addrse = JoinDate.Manufacturer.CarAddres

            }).FirstOrDefault();

Join参数1是关联的对象,参数2,3是分别可以关联上的字段,参数4是关联后返回的最终结果。

数据分组Group

声明式

  var query = from car in cars
                        group car by car.FCPHK into  manufactureGroup
                        orderby manufactureGroup.Key descending
                        select manufactureGroup;

如果需要对声明式的分组进行排序,需要用到into 关键字,最后返回select分完组并排序的结果。

命令式:

var query2 = cars.GroupBy(c=>c.FCPHK).OrderByDescending(g=>g.Key);

数据分组连接groupjoin

声明式

     var query = from manufacture in manufacturers
                        join car in cars on manufacture.CarName equals car.CarName
                        into CarGroup
                        orderby manufacture.CarName descending
                        select new
                        {
                            Manufacture= manufacture,
                            Cars= CarGroup
                        };

命令式

 var quer2 = manufacturers.GroupJoin(cars, m => m.CarName, c => c.CarName, (m, CarGroup) => new
            {
                Manufacture = m,
                Cars = CarGroup
            }).OrderByDescending(m => m.Manufacture.CarName);

数据聚合

声明式

     var quer2 = from car in cars
                        group car by car.FCPHK into GroupCar
                        select new
                        {
                            FCPHK = GroupCar.Key,
                            Avg = GroupCar.Average(c => c.FCPHK),
                            Max = GroupCar.Max(c => c.FCPHK),
                            Min = GroupCar.Min(c => c.FCPHK)
                        } into AverageFCPHK
                        orderby AverageFCPHK.Avg descending
                        select AverageFCPHK;
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值