首页 > 编程语言 >C# LINQ

C# LINQ

时间:2023-05-29 22:03:07浏览次数:47  
标签:Console C# list LINQ Add WriteLine Employee new

视频链接:.NET 6教程,.Net Core 2022视频教程,杨中科主讲_哔哩哔哩_bilibili

Lambda 与 LINQ

为啥要学LINQ?

让数据处理变得简单。

【复习】委托
1、委托是可以指向方法的类型,调用委托变量时执行的就是变量指向的方法。
2、.NET 中定义了泛型委托Action(无返回值)和Func(有返回值),所以一般不用自定义委托类型。

Lambda是怎么来的?

委托变量不仅可以指向普通方法,还可以指向匿名方法。

static void Main(String[] args) {
    Func<int, int, int> func = delegate (int x, int y) {
        return x + y;
    };
    Console.WriteLine(func(1, 2));

    Action<string> action = delegate (string s) { 
        Console.WriteLine(s); 
    };
    action("Hello");
}

匿名方法可以写成Lambda表达式。
可以省略参数数据类型,因为编译器能根据委托类型推断出参数的类型,用=>引出来方法体。
如果=>之后的方法体中只有一行代码,且方法有返回值,那么可以省略方法体的{}以及return。
如果只有一个参数,参数的(可以省略)。
如果委托没有返回值,且方法体只有一行代码,可省略{}

static void Main(String[] args) {
    Action<string> action = (string s) => {
        Console.WriteLine(s);
    };
    action("World");

    Action<string> action2 = s => {
        Console.WriteLine(s);
    };
    action2("World");

    Action<string> action3 = s => Console.WriteLine(s);
	action3("World");
}

探秘LINQ方法的背后

LINQ中提供了很多集合的扩展方法,配合lambda能简化数据处理。

static void Main(String[] args) {
    int[] nums = { 11, 23, 6, 332, 1521, 44, 2 };
    // Where方法会遍历集合中每个元素,
    // 对于每个元素都调用i=>i>100这个Lambda表达式判断一下是否为true,
    // 如果为true,则把这个元素放到返回的集合中
    IEnumerable<int> result = nums.Where(i => i > 100);

    // 自定义方法实现where这个扩展方法的功能
    //IEnumerable<int> result = MyWhere(nums, i => i > 100);
    //IEnumerable<int> result = MyWhere2(nums, i => i > 100);

    foreach (int i in result) {
        Console.WriteLine(i);
    }
}

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

static IEnumerable<int> MyWhere2(IEnumerable<int> nums, Func<int, bool> func) {
    foreach (int i in nums) {
        if (func(i)) {
            yield return i;
        }
    }
}

可以使用var让编译器的“类型推断”来简化类型的声明。在LINQ中常用。
C#的var和JavaScript的var不一样,仍然是强类型的。C#中的弱类型是dynamic

常用扩展方法

常用扩展方法一:Where、Count、Any方法

LINQ中提供了大量类似Where的扩展方法,简化数据处理。大部分都在System.Linq命名空间中。

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

(2)
Count方法:获取数据条数

(3)
Any()方法:是否至少有一条数据【有可能效率比Count高】

static void Main(String[] args) {
    List<Employee> list = new List<Employee>();
    list.Add(new Employee(1, "zhangsanA", 20, true, 5000));
    list.Add(new Employee(2, "zhangsanB", 26, false, 4000));
    list.Add(new Employee(3, "zhangsanC", 31, true, 8000));
    list.Add(new Employee(4, "zhangsanD", 35, false, 2000));
    list.Add(new Employee(5, "zhangsanE", 43, true, 5000));
    list.Add(new Employee(6, "zhangsanF", 35, true, 8000));

    IEnumerable<Employee> items1= list.Where(e => e.Age > 30);
    foreach(var i in items1) {
        Console.WriteLine(i);
    }

    Console.WriteLine(list.Count());
    Console.WriteLine(list.Count(e => e.Age > 30));
    Console.WriteLine(list.Count(e => e.Age > 30 && e.Salary > 5000));

    Console.WriteLine(list.Any(e => e.Age == 20));
    Console.WriteLine(list.Any(e => e.Salary > 8000));
}

常用扩展方法二

获取一条数据的方法 Single、SingleOrDefault、First、FirstOrDefault

获取一条数据(是否带参数的两种写法):
(1)Single:有且只有一条满足要求的数据;
(2)SingleOrDefault:最多只有一条满足要求的数据;
(3)First:至少有一条,返回第一条【一个都没有,会出错】;
(4)FirstOrDefault:返回第一条或者默认值;
选择合适的方法,“防御性编程”

static void Main(String[] args) {
    List<Employee> list = new List<Employee>();
    list.Add(new Employee(1, "zhangsanA", 20, true, 5000));
    list.Add(new Employee(2, "zhangsanB", 26, false, 4000));
    list.Add(new Employee(3, "zhangsanC", 31, true, 8000));
    list.Add(new Employee(4, "zhangsanD", 35, false, 2000));
    list.Add(new Employee(5, "zhangsanE", 43, true, 5000));
    list.Add(new Employee(6, "zhangsanF", 35, true, 8000));

    // 测试返回一条数据的扩展方法
    //list.Single();// 有多条数据,会抛出异常
    Employee e1 = list.Where(e => e.Name == "zhangsanA").Single();
    Console.WriteLine(e1);

    IEnumerable<Employee> eitems = list.Where(e => e.Name == "zhangsanA");
    Employee e2 = eitems.Single();
    Console.WriteLine(e2);

    var e3 = list.Single(e => e.Name == "zhangsanA");// Single里面也能写条件
    Console.WriteLine(e3);

    var e4 = list.Where(e => e.Name == "lisi").Single();// 如果没有一条数据,也会抛出异常
    Console.WriteLine(e4);
}
static void Main(String[] args) {
    int[] nums2 = { 3, 5, 7 };
    
    int i = nums2.SingleOrDefault(e => e > 5);
    Console.WriteLine(i);

    //0 没有一条数据满足,返回默认值
    int i2= nums2.SingleOrDefault(i => i > 8);
    Console.WriteLine(i2);

    // 如果有多条数据,会抛出异常
    int i3 = nums2.SingleOrDefault(e => e > 4);
    Console.WriteLine(i3);
}

排序 Order、OrderByDescending

(1)Order():对数据正序排序;
(2)OrderByDescending()倒序排序;
list.OrderBy(e => e.Age);
对于简单类型排序,也许不用lambda表达式。特殊案例:按照最后一个字排序;用Guid或随机数讲行随机排序。

static void Main(String[] args) {
    List<Employee> list = new List<Employee>();
    list.Add(new Employee(1, "zhangsanA", 20, true, 5000));
    list.Add(new Employee(2, "zhangsanB", 26, false, 4000));
    list.Add(new Employee(3, "zhangsanC", 31, true, 8000));
    list.Add(new Employee(4, "zhangsanD", 35, false, 2000));
    list.Add(new Employee(5, "zhangsanE", 43, true, 5000));
    list.Add(new Employee(6, "zhangsanF", 35, true, 8000));

    IEnumerable<Employee> employees = list.OrderBy(e => e.Salary);//升序
    //IEnumerable<Employee> employees = list.OrderByDescending(e => e.Salary);//降序
    foreach (Employee employee in employees) {
        Console.WriteLine(employee);
    }
}

多规则排序:
可以在Order()、OrderByDescending()后继续写ThenBy()、ThenByDescending()
案例:优先按照Age排序,如果Age相同再按照Salary排序
list.OrderBy(e => e.Age).ThenByDescending(e=>e.Salary)

限制结果集,获取部分数据 Skip(n)、Take(n)

Skip(n)跳过n条数据,Take(n)获取n条数据。
案例:获取从第2条开始获取3条数据 var orderedltems1 = list.Skip(2).Take(3);
Skip()、Take()也可以单独使用。


static void Main(String[] args) {
    List<Employee> list = new List<Employee>();
    list.Add(new Employee(1, "zhangsanA", 20, true, 5000));
    list.Add(new Employee(2, "zhangsanB", 26, false, 4000));
    list.Add(new Employee(3, "zhangsanC", 31, true, 8000));
    list.Add(new Employee(4, "zhangsanD", 35, false, 2000));
    list.Add(new Employee(5, "zhangsanE", 43, true, 5000));
    list.Add(new Employee(6, "zhangsanF", 35, true, 8000));

    IEnumerable<Employee> employees = list.Skip(3).Take(2);
	foreach (Employee employee in employees) {
   		Console.WriteLine(employee);
	}
}

常用扩展方法三

聚合函数 Max()、Min()、Average()、Sum()、Count()

分组 GroupBy()

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

static void Main(String[] args) {
    List<Employee> list = new List<Employee>();
    list.Add(new Employee(1, "zhangsanA", 20, true, 5000));
    list.Add(new Employee(2, "zhangsanB", 26, false, 4000));
    list.Add(new Employee(3, "zhangsanC", 31, true, 8000));
    list.Add(new Employee(4, "zhangsanD", 35, false, 2000));
    list.Add(new Employee(5, "zhangsanE", 43, true, 5000));
    list.Add(new Employee(6, "zhangsanF", 35, true, 8000));

    // select Salary,Max(age) from t group by Salary;
    IEnumerable<IGrouping<int,Employee>> items= list.GroupBy(e => e.Salary);
    foreach (IGrouping<int, Employee> item in items) {
        Console.WriteLine(item.Key);
        Console.WriteLine("最大年龄:" + item.Max(e => e.Age));
        foreach (Employee emp in item) {
            Console.WriteLine(emp);
        }
        Console.WriteLine("**********************");
    }

    Console.WriteLine("**********************");

    // 示例2:根据年龄分组,获取每组的总人数、最高工资、平均工资
    var items2 = list.GroupBy(e => e.Age);
    foreach (var emp in items2) {
        Console.WriteLine("总人数:" + emp.Count());
        Console.WriteLine("最高工资:" + emp.Max(e => e.Salary));
        Console.WriteLine("平均工资:" + emp.Average(e => e.Salary));
    }
}

常用扩展方法四

投影 Select()

把集合中的每一项(逐个的)转换为另外一种类型。

static void Main(String[] args) {
    List<Employee> list = new List<Employee>();
    list.Add(new Employee(1, "zhangsanA", 20, true, 5000));
    list.Add(new Employee(2, "zhangsanB", 26, false, 4000));
    list.Add(new Employee(3, "zhangsanC", 31, true, 8000));
    list.Add(new Employee(4, "zhangsanD", 35, false, 2000));
    list.Add(new Employee(5, "zhangsanE", 43, true, 5000));
    list.Add(new Employee(6, "zhangsanF", 35, true, 8000));

    IEnumerable<int> ints =list.Select(e => e.Salary);
    foreach (int i in ints) {
        Console.WriteLine(i);
    }

    IEnumerable<string> strs = list.Where(e=>e.Gender==true).Select(e => e.Name);
    foreach (string i in strs) {
        Console.WriteLine(i);
    }

    IEnumerable<string> strs2= list.Select(e => e.Gender ? "男" : "女");
    foreach (string i in strs2) {
        Console.WriteLine(i);
    }
}

匿名方法 var [经常结合Select使用]
image.png

投影与匿名类型

static void Main(String[] args) {
    List<Employee> list = new List<Employee>();
    list.Add(new Employee(1, "zhangsanA", 20, true, 5000));
    list.Add(new Employee(2, "zhangsanB", 26, false, 4000));
    list.Add(new Employee(3, "zhangsanC", 31, true, 8000));
    list.Add(new Employee(4, "zhangsanD", 35, false, 2000));
    list.Add(new Employee(5, "zhangsanE", 43, true, 5000));
    list.Add(new Employee(6, "zhangsanF", 35, true, 8000));
    
    var items= list.Select(e => new { Xingming = e.Name, Nianling = e.Age, Xingbie = e.Gender ? "男" : "女" });
	foreach(var i in items) {
    	Console.WriteLine(i.Xingming + ":" + i.Xingbie);
	}
}

image.png

链式调用

集合转换

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

image.png

链式调用

Where、Select、OrderBy、GroupBy、Take、Skip等返回值都是IEnumerable类型,所有可以链式调用。

LINQ另外一种倩影——查询语法

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

对比:
image.png

标签:Console,C#,list,LINQ,Add,WriteLine,Employee,new
From: https://www.cnblogs.com/swbna/p/17441769.html

相关文章

  • springboot集成themeleaf报Namespace 'th' is not bound问题的解决
    问题描述在我们想要在html前端页面使用th:符号时,发现他一直报错问题解决在html标签的最上方,也就是这里:加上这样一句代码:(加在html标签里面!!!)xmlns="http://www.w3.org/1999/xhtml"xmlns:th="http://www.thymeleaf.org"这样就能够解决这个问题啦!......
  • 十一、JUC-synchronized与锁升级
    零、问题谈谈你对Synchronized的理解Synchronized的锁升级你聊聊Synchronized的性能是不是一定弱于Locksynchronized锁:由对象头中的MarkWord根据锁标志位的不同而被复用及锁升级策略一、Synchronized的性能变化1、java5之前java5以前,只有Synchronized,这个是操作系统级......
  • 【2023 · CANN训练营第一季】——Ascend C算子背后的魔法
    前言:TIKC++,2023年CANN的一个神奇魔法,得益于TIKC++算子的孪生调试技术,我们可以了解到更多的技术细节,本文试图对隐藏在多核并行,流水计算、dobulebuffer背后的CANNAscendC算子魔法进行摸索和理解,是什么样的技术让用户编写的简单代码可以先实现上述神奇的功能。本文没有请专业人士......
  • facebook console.log bug All In One
    facebookconsole.logbugAllInOneconsole.logURLlinkbugerrors❌console.log(`查看https://www.facebook.com/selfxss详细了解。`)//查看https://www.facebook.com/selfxss详细了解。solutionaddwhitespacesbetweenURLandtext✅在链接与文字之间,添......
  • 【蓝桥杯集训·每日一题】AcWing 4496. 吃水果
    写在前面本人CSDN博客主页:这里一、题目1、原题链接4496.吃水果2、题目描述n个小朋友站成一排,等着吃水果。一共有m种水果,每种水果的数量都足够多。现在,要给每个小朋友都发一个水果,要求:在所有小朋友都拿到水果后,恰好有k个小朋友拿到的水果和其左边相邻小朋友拿到的水果不同(最左......
  • net-core(EF Core)-使用表达式树还是委托
    usingMicrosoft.EntityFrameworkCore;usingMicrosoft.EntityFrameworkCore.Metadata.Builders;publicclassMemberConfig:IEntityTypeConfiguration<Member>{publicvoidConfigure(EntityTypeBuilder<Member>builder){builder.ToTa......
  • [NextJS] getStaticProps
    Continue... Ref: Next.js产品级的React框架-中文开发入门教学-编写静态页面属性getStaticProps  为了爬虫,所以这么写。importHeadfrom'next/head'exportdefaultfunctionHome(props){const{datalist}=props;return(<div>......
  • 【Socket】基于UDP的发送端和接收端
    UDP和TCP的差异UDP相比TCP,无需在连接状态下交换数据,因此UDP的server端和client端无需经过连接过程,即不必调用listen()和accept()函数。UDP中只有创建套接字和数据交换的过程。基于UDP的接收和发送函数当创建好TCP套接字后,传输数据时无需再添加地址信息,因此TCP套接字会保持与对......
  • [转]关于Visual Studio:如何使用cmake检测64位MSVC?
    1、如何使用cmake检测64位MSVC?2、关于VisualStudio:如何使用cmake检测64位MSVC?......
  • C++ Primer 第一、二章 C++基础,变量和基本类型
    一、C++基础<iostream>包含两个基础类型,istream-输入流和ostrea-输出流。标准库定义了四个IO对象cin-标准输入(istream),cout-标准输出(o),cerr-标准错误(o),clog-用来输出程序运行时的一般性信息(o)。 #include<iostream>intmain(){std::cout<<"Enter"<<std:......