前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >LINQ常用扩展方法、委托、Lambda、yield

LINQ常用扩展方法、委托、Lambda、yield

作者头像
鱼找水需要时间
发布2024-03-23 08:03:45
660
发布2024-03-23 08:03:45
举报
文章被收录于专栏:SpringBoot教程SpringBoot教程

LINQ让数据处理变得简单

Where方法

 每一项数据都会经过predicate的测试,如果针对一个元素,predicate执行的返回值为true,那么这个元素就会放到返回值中。 Where参数是一个lambda表达式格式的匿名方法,方法的参数e表示当前判断的元素对象。参数的名字不一定非要叫e,不过一般lambda表达式中的变量名长度都不长。

代码语言:javascript
复制
 static void Main(string[] args)
 {
     List<Employee> list = new List<Employee>();
     list.Add(new Employee { Id = 1, Name = "张三", Age = 30, Gender = false, Salary = 3500});
     list.Add(new Employee { Id = 2, Name = "李四", Age = 48, Gender = false, Salary = 6000});
     list.Add(new Employee { Id = 3, Name = "王五", Age = 16, Gender = true, Salary = 2800});
     list.Add(new Employee { Id = 4, Name = "赵六", Age = 16, Gender = false, Salary = 4100});
     list.Add(new Employee { Id = 5, Name = "田七", Age = 33, Gender = true, Salary = 3000});

     IEnumerable<Employee> items = list.Where(e => e.Age > 40);
     foreach (var item in items)
     {
         Console.WriteLine(item);
     }
 }
 class Employee
 {
     public long Id { 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 $"Id={Id},Name={Name},Age={Age},Gender={Gender},Salary={Salary}";
     }
 }

Count()方法

获取数据条数

代码语言:javascript
复制
int count1 = list.Count(e => e.Salary > 5000 || e.Age < 30);
int count2 = list.Where(e => e.Salary > 5000 || e.Age < 30).Count();

Any()方法

是否至少有一条数据

代码语言:javascript
复制
bool b1 = list.Any(e => e.Salary > 8000);
bool b2 = list.Where(e => e.Salary > 8000).Any();

比Count()实现效率高。

获取一条数据(是否带参数的两种写法)

Single

有且只有一条满足要求的数据,如果都不满足或者满足多条数据则抛出异常。

代码语言:javascript
复制
Employee e1= list.Where(e => e.Id == 4).Single();
Employee e2= list.Single(e => e.Id == 4);
Console.WriteLine(e2);
SingleOrDefault

最多只有一条满足要求的数据,如果都不满足返回默认值,如果满足多条则抛出异常。

代码语言:javascript
复制
Employee e2 = list.SingleOrDefault(e => e.Id == 4);
Employee e3 = list.SingleOrDefault(e => e.Id == 10);
Console.WriteLine(e3 == null);
First

至少有一条,返回第一条,如果都不满足抛出异常

代码语言:javascript
复制
Employee e4 = list.First(e => e.Age > 30);
Employee e5 = list.First(e => e.Age > 100);
FirstOrDefault

返回第一条或者默认值

代码语言:javascript
复制
Employee e6 = list.FirstOrDefault(e => e.Age > 100);
Console.WriteLine(e6 == null);

排序

Order() 对数据正序排序;

代码语言:javascript
复制
list.OrderBy(e => e.Age);

OrderByDescending() 倒序排序;

代码语言:javascript
复制
IEnumerable<Employee>  list2= list.OrderByDescending(e => e.Age);

用Guid或者随机数进行随机排序:

代码语言:javascript
复制
IEnumerable<Employee>  list2= list.OrderBy(e => Guid.NewGuid());

Random random = new Random(); 
IEnumerable<Employee>  list2= list.OrderBy(e => random.Next());

按照最后一个字符排序:

代码语言:javascript
复制
IEnumerable<Employee>  list2= list.OrderBy(e => e.Name[e.Name.Length - 1]);
多规则排序

可以在Order()OrderByDescending()后继续写ThenBy ()ThenByDescending()。 优先按照Age排序,如果Age相同再按照Salary排序

代码语言:javascript
复制
list.OrderBy(e => e.Age).ThenByDescending(e => e.Salary)
// 千万不要写成
// list.OrderBy(e => e.Age).OrderByDescending(e => e.Salary)

限制结果集,获取部分数据

Skip(n)跳过n条数据,Take(n)获取n条数据。 获取从第2条开始获取3条数据:

代码语言:javascript
复制
var orderedItems1 = list.Skip(2).Take(3);

Skip()Take()也可以单独使用。

代码语言:javascript
复制
var orderedItems1 = list.Skip(2);
var orderedItems2 = list.Take(3);

Tips:LINQ中所有的扩展方法几乎都是针对IEnumerable接口的,而几乎所有能返回集合的都返回IEnumerable,所以是可以把几乎所有方法“ 链式使用 ”的。

聚合函数

Max()Min()Average()Sum()Count()

代码语言:javascript
复制
//最大年龄
int a = list.Max(e => e.Age);
//最小年龄
int a = list.Min(e => e.Age);

//年龄大于等于30岁的平均年龄
double b = list.Where(e => e.Age >= 30).Average(e => e.Age);

//集合中所有年龄的和
int sum = list.Sum(e => e.Age);
//集合个数
int count = list.Count();

分组

GroupBy()方法参数是分组条件表达式,返回值为IGrouping<TKey, TSource>类型的泛型IEnumerable,也就是每一组以一个IGrouping对象的形式返回。IGrouping是一个继承自IEnumerable的接口,IGroupingKey属性表示这一组的分组数据的值。

代码语言:javascript
复制
IEnumerable<IGrouping<int, Employee>> g = list.GroupBy(x => x.Age);
foreach (IGrouping<int, Employee> item in g)
{
    Console.WriteLine(item.Key);
    foreach (var e in item)
    {
        Console.WriteLine(e);
    }

} 

投影

 投影是把集合中的每一项转换为另外一种类型。

代码语言:javascript
复制
IEnumerable<int> ages = list.Select(e => e.Age);
IEnumerable<string> names = list.Select(e=>e.Gender?"男":"女");
var dogs = list.Select(p=>new Dog{NickName=e.Name,Age=e.Age});

匿名类型

代码语言:javascript
复制
var p = new {Name="tom", Id=1};
//属性名称一样时,可以省略
var p1 = new {name, Id=1, p.Age};
代码语言:javascript
复制
var select = list.Select(e => new { NianLing = e.Age, XingBie = e.Gender ? "男" : "女" });
foreach (var item in select)
{
  Console.WriteLine(item.NianLing + "," + item.XingBie);
}      
代码语言:javascript
复制
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)});

通过反编译软件查看dll文件,编译器最后也是生成了具体的类,只不过这个类名是编译器自动生成的。

集合转换

 有一些地方需要数组类型或者List类型的变量,可以用ToArray()方法和ToList()分别把IEnumerable<T>转换为数组类型和List<T>类型。

查询语法

 使用Where、OrderBy、Select等 扩展方法进行数据查询的写法叫做 “LINQ方法语法”。还有一种“查询语法”的写法。

代码语言:javascript
复制
var items2 = from e in list
            where e.Salary > 3000
            orderby e.Age
            select new { e.Name, e.Age, Gender = e.Gender ? "男" : "女" };
//等同于以下写法
var items3 = list.Where(e => e.Salary > 3000).OrderBy(e => e.Age).
    Select(e => new { e.Name, e.Age, Gender = e.Gender ? "男" : "女" });

Tips:日常开发推荐方法语法

统计一个字符串中每个字母出现的频率(忽略大小写),然后按照从高到低的顺序输出出现频率高于2次的单词和其出现的频率:

代码语言:javascript
复制
var items = s.Where(c => char.IsLetter(c))//过滤非字母
    .Select(c => char.ToLower(c))//大写字母转换为小写
    .GroupBy(c => c)//根据字母进行分组
    .Where(g=>g.Count()>2)//过滤掉出现次数<=2
    .OrderByDescending(g => g.Count())//按次数排序
    .Select(g=>new { Char=g.Key,Count=g.Count()});

委托

1、委托是可以指向方法的类型,调用委托变量时执行的就是变量指向的方法。

代码语言:javascript
复制
static void Main(string[] args)
{
    D1 d = F1;
    d();
}
static void F1()
{
    Console.WriteLine("hello");
}
delegate void D1();

匿名方法

代码语言:javascript
复制
static void Main(string[] args)
{
    Action a = delegate() {
        Console.WriteLine("hello world");
    };
    a();
}
代码语言:javascript
复制
static void Main(string[] args)
{
    Action a = delegate() {
        Console.WriteLine("hello world");
    };
    Func<int, int, int> func = delegate (int a, int b)
    {
        return a + b;
    };
    Console.WriteLine(func(1, 2));
}
Lambda表达式
代码语言:javascript
复制
Func<int, int, string> f1 = (i1,i2) =>{
    return $"{i1}+{i2}={i1 + i2}";
};
  • 可以省略参数数据类型,因为编译能根据委托类型推断出参数的类型,用=>引出来方法体。
  • 如果委托没有返回值,且方法体只有一行代码,可省略 {}
  • 如果=>之后的方法体中只有一行代码,且方法有返回值,那么可以省略方法体的{}以及return。
  • 如果只有一个参数,参数的()可以省略。

2、.NET 中定义了泛型委托Action(无返回值)和Func(有返回值),所以一般不用自定义委托类型。

代码语言:javascript
复制
static void Main(string[] args)
{
    Action a = F1;
    a();
}
static void F1()
{
    Console.WriteLine("hello");
}
代码语言:javascript
复制
static void Main(string[] args)
{
    Func<int, int, int> func = F2;
    int sum = func(2, 5);
    Console.WriteLine(sum);
}
static int F2(int a, int b)
{
    return a + b;
}
LINQ

筛选出数组中大于3的数字:

代码语言:javascript
复制
IEnumerable<int> ints = [ 2,3,4,5,5];
IEnumerable<int> result = ints.Where(a => a > 3);

通过编写扩展方法MyWhere来模拟Where的实现:

代码语言:javascript
复制
static void Main(string[] args)
{
    IEnumerable<int> ints = [ 2,3,4,5,5];
    //IEnumerable<int> result = ints.Where(a => a > 3);
    IEnumerable<int> result = MyWhere(ints, a => a > 3);
    foreach (var item in result)
    {
        Console.WriteLine(item);
    }
}

static IEnumerable<int> MyWhere(IEnumerable<int> ints, Func<int, bool> func)
{
    List<int> result = new List<int>();
    foreach (var item in ints)
    {
        if(func(item)) result.Add(item);
    }
    return result;
}
yield return

通过yield return来让MyWhere“流水线”处理:

代码语言:javascript
复制
static void Main(string[] args)
{
    IEnumerable<int> ints = [ 2,3,4,5,5];
    //IEnumerable<int> result = ints.Where(a => a > 3);
    IEnumerable<int> result = MyWhere(ints, a => a > 3);
    foreach (var item in result)
    {
        Console.WriteLine(item);
    }
}
static IEnumerable<int> MyWhere(IEnumerable<int> ints, Func<int, bool> func)
{
    List<int> result = new List<int>();
    foreach (var item in ints)
    {
        if(func(item)) yield return item;
    }
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2024-03-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Where方法
  • Count()方法
  • Any()方法
  • 获取一条数据(是否带参数的两种写法)
    • Single
      • SingleOrDefault
        • First
          • FirstOrDefault
          • 排序
            • 多规则排序
            • 限制结果集,获取部分数据
            • 聚合函数
            • 分组
            • 投影
            • 匿名类型
            • 集合转换
            • 查询语法
            • 委托
              • Lambda表达式
                • LINQ
                  • yield return
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档