C# 基础知识系列-7 Linq详解
前言
在上一篇中简单介绍了Linq的入门级用法,这一篇尝试讲解一些更加深入的使用方法,与前一篇的结构不一样的地方是,这一篇我会先介绍Linq里的支持方法,然后以实际需求为引导,分别以方法链的形式和类SQL的形式写出来。
前置概念介绍
Predicate<T>谓词、断言,等价于Func<T,bool>即返回bool的表达式Expression<TDelegate>表达式树,这个类很关键,但是在这里会细说,我们会讲它的一个特殊的泛型类型:Expression<Func<T,bool>>这个在某些数据源的查询中十分重要,它代表lambda表达式中一种特殊的表达式,即没有大括号和return关键字的那种。
我们先准备两个类:
- Student/学生类:
/// <summary>
/// 学生
/// </summary>
public class Student
{
/// <summary>
/// 学号
/// </summary>
public int StudentId { get; set; }
/// <summary>
/// 姓名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 班级
/// </summary>
public string Class { get; set; }
/// <summary>
/// 年龄
/// </summary>
public int Age { get; set; }
}
Subject/科目类:
/// <summary>
/// 科目
/// </summary>
public class Subject
{
/// <summary>
/// 名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 年级
/// </summary>
public string Grade { get; set; }
/// <summary>
/// 学号
/// </summary>
public int StudentId { get; set; }
/// <summary>
/// 成绩
/// </summary>
public int Score { get; set; }
}
Subject 和Student通过学号字段一一关联,实际工作中数据表有可能会设计成这。
那么先虚拟两个数据源:IEnumerable<Student> students 和 IEnumerable<Subject> subjects。先忽略这两个数据源的实际来源,因为在开发过程中数据来源有很多种情况,有数据库查询出来的结果、远程接口返回的结果、文件读取的结果等等。不过最后都会整理成IEnumerable<T>的子接口或实现类的对象。
常见方法介绍
Where 过滤数据,查询出符合条件的结果
where的方法声明:
public IEnumerable<TSource> Where<TSource> (this IEnumerable<TSource> source, Func<TSource,bool> predicate)
可以看出不会转换数据类型,通过给定的lambda表达式或者一个方法进行过滤,获取返回true的元素。
示例:
// 获取年纪大于10但不大于12的同学们
List<Student> results = students.Where(t=>t.Age >10 && t.Age<= 12).ToList();
注意在调用ToList之后数据才会实质上查询出来。
Group 分组,依照指定内容进行分组
Group的方法声明有很多种:
最常用的一种是:
public static IEnumerable<System.Linq.IGrouping<TKey,TSource>> GroupBy<TSource,TKey> (this IEnumerable<TSource> source, Func<TSource,TKey> keySelector);
示例:
//将学生按照班级进行分组
List<IGrouping<string,Student>> list = students.GroupBy(p => p.Class).ToList();
OrderBy/OrderByDescending 进行排序,按条件升序/降序
它们是一对方法,一个是升序一个降序,其声明是一样的:
常用的是:
public static System.Linq.IOrderedEnumerable<TSource> OrderBy<TSource,TKey> (this IEnumerable<TSource> source, Func<TSource,TKey> keySelector);
示例:
//按年龄的升序排列:
List<Student> results = students.OrderBy(p => p.Age).ToList();
//按年龄的降序排列:
List<Student> results = students.OrderByDescending(p => p.Age).ToList();
First/Last 获取数据源的第一个/最后一个
这组方法有两个常用的重载声明:
First:
// 直接获取第一个
public static TSource First<TSource> (this IEnumerable<TSource> source);
// 获取满足条件的第一个
public static TSource First<TSource> (this IEnumerable<TSource> source, Func<TSource,bool> predicate);
Last:
// 直接获取最后一个
public static TSource Last<TSource> (this IEnumerable<TSource> source);
// 获取最后一个满足条件的元素
public static TSource Last<TSource> (this IEnumerable<TSource> source, Func<TSource,bool> predicate);
示例:
Student student = students.First();// 等价于 students[0];
Student student = students.First(p=>p.Class == "一班");//获取数据源中第一个一班的同学
Student student = students.Last();//最后一个学生
Student student = students.Last(p=>p.Class == "三班");//获取数据源中最后一个三班的同学
注意:
- 在某些数据源中使用Last会报错,因为对于一些管道类型的数据源或者说异步数据源,程序无法确认最后一个元素的位置,所以会报错。解决方案:先使用OrderBy对数据源进行一次排序,使结果与原有顺序相反,然后使用First获取
- 当数据源为空,或者不存在满足条件的元素时,调用这组方法会报错。解决方案:调用FirstOrDefault/LastOrDefault,这两组方法在无法查询到结果时会返回一个默认值。
Any/All 是否存在/是否都满足
Any:是否存在元素满足条件
有两个版本,不过意思可能不太一样:
public static bool Any<TSource> (this IEnumerable<TSource> source);//数据源中是否有数据
//================
//是否存在满足条件的数据
public static bool Any<TSource> (this IEnumerable<TSource> source, Func<TSource,bool> predicate);
All :是否都满足条件:
public static bool Any<TSource> (this IEnumerable<TSource> source, Func<TSource,bool> predicate);
示例:
// 是否有学生
bool isAny = students.Any();
// 是否有五班的同学
bool isFive = students.Any(p=>p.Class == "五班");
// 是否所有学生的年纪都不小于9岁
bool isAll = students.All(p=>p.Age >= 9);
Skip 略过几个元素
Skip一共有三个衍生方法:
第一个:Skip 自己: 略过几个元素,返回剩下的元素内容
public static IEnumerable<TSource> Skip<TSource> (this IEnumerable<TSource> source, int count);
第二个:SkipLast,从尾巴开始略过几个元素,返回剩下的元素内容
public static IEnumerable<TSource> SkipLast<TSource> (this IEnumerable<TSource> source, int count);
第三个:SkipWhile,跳过满足条件的元素,返回剩下的元素
public static IEnumerable<TSource> SkipWhile<TSource> (this IEnumerable<TSource> source, Func<TSource,bool> predicate);
示例:
// 不保留前10个学生
List<Student> results = students.Skip(10).ToList();
// 不保留后10个学生
List<Student> results = students.SkipLast(10).ToList();
// 只要非一班的学生
List<Student> results = students.SkipWhere(p=>p.Class=="一班").ToList();
//上一行代码 等价于 = students.Where(p=>p.Class != "一班").ToList();
Take 选取几个元素
Take与Skip一样也有三个衍生方法,声明的参数类型也一样,这里就不对声明做介绍了,直接上示例。
//选取前10名同学
List<Student> results = students.Take(10).ToList();
// 选取最后10名同学
List<Student> results = students.TakeLast(10).ToList();
//选取 一班的学生
List<Student> results = students.TakeWhile(p=>p.Class=="一班").ToList();
// 上一行 等价于 = students.Where(p=>p.Class=="一班").ToList();
在使用Linq写分页的时候,就是联合使用Take和Skip这两个方法:
int pageSize = 10;//每页10条数据
int pageIndex = 1;//当前第一页
List<Student> results = students.Skip((pageIndex-1)*pageSize).Take(pageSize).ToList();
其中 pageIndex可以是任意大于0 的数字。Take和Skip比较有意思的地方就是,如果传入的数字比数据源的数据量大,根本不会爆粗,只会返回一个空数据源列表。
Select 选取
官方对于Select的解释是,将序列中的每个元素投影到新的表单里。我的理解就是,自己 定义一个数据源单个对象的转换器,然后按照自己的方式对数据进行处理,选择出一部分字段,转换一部分字段。
所以按我的理解,我没找到java8的同效果方法。(实际上java用的是map,所以没找到,
C# 基础知识系列-7 Linq详解的更多相关文章
- vue.js基础知识篇(6):组件详解
第11章:组件详解 组件是Vue.js最推崇也最强大的功能之一,核心目标是可重用性. 我们把组件代码按照template.style.script的拆分方式,放置到对应的.vue文件中. 1.注册 V ...
- 《Java基础知识》Java注解"@"详解
Java注解含义: Java注解,顾名思义,注解,就是对某一事物进行添加注释说明,会存放一些信息,这些信息可能对以后某个时段来说是很有用处的.Java注解又叫java标注,java提供了一套机制,使得 ...
- 《Java基础知识》Java锁详解(volatile,synchronized等)
volatile: 让变量每次在使用的时候,都从主存中取. volatile具有synchronized关键字的“可见性”,但是没有synchronized关键字的“并发正确性”,也就是说不保证线程执 ...
- linux基础知识3_根文件系统详解
文件系统: rootfs:根文件系统 /boot:系统启动相关的文件,如内核.initrd以及grub /dev:设备文件 块设备:随机访问 字符设备:线性访问,按字符为单位 设备号:主设备号(maj ...
- JavaScript基础知识之——Location 对象详解
属性 描述 location.hash 设置或取得 URL 中的锚 location.host 设置或取得 URL 中主机(包括端口号) location.hostname 设置或取得 URL 中的主 ...
- vue.js基础知识篇(2):指令详解
第三章:指令 1.语法 指令以v-打头,它的值限定为绑定表达式,它负责的是按照表达式的值应用某些行为到DOM上. 内部指令有v-show,v-else,v-model,v-repeat,v-for,v ...
- 《Java基础知识》Java字符串详解
本文内容: String类的概述 String类的使用步骤 String类的常用方法 本文目的: 能够使用String类的构造方法创建字符串对象 能够明确String类的构造方法创建对象,和直接赋值创 ...
- 《Java基础知识》Java异常处理详解
1. Java 中的异常 前言:Java 中的异常处理是处理程序运行错误时的强大机制之一,它可以保证应用程序的正常流程. 首先我们将了解java异常.异常的类型以及受查和非受查异常之间的区别. 1.1 ...
- 《Java基础知识》Java 泛型详解
JDK 1.5 之后,Java 通过泛型解决了容器类型安全这一问题,而几乎所有人接触泛型也是通过Java的容器.那么泛型究竟是什么? 泛型的本质是参数化类型:也就是说,泛型就是将所操作的数据类型作为参 ...
随机推荐
- ysoserial源码结构分析
1.前言 之前也花了几天晚上熟悉了一下commonscollections系列的构造,那么学习一下这个项目是如何设计的也挺重要,多学习大佬如何写代码应该也能对自己的代码能力有提升吧~2333 2.项目 ...
- 通过filebeat、logstash、rsyslog采集nginx日志的几种方式
由于nginx功能强大,性能突出,越来越多的web应用采用nginx作为http和反向代理的web服务器.而nginx的访问日志不管是做用户行为分析还是安全分析都是非常重要的数据源之一.如何有效便捷的 ...
- 峰哥说技术:04-Spring Boot基本配置
Spring Boot深度课程系列 峰哥说技术—2020庚子年重磅推出.战胜病毒.我们在行动 04 Spring Boot基本配置 1)容器的相关配置 在Spring Boot中可以内置Tomcat. ...
- CSS3新单位vw,vh,vmin,vmax详解
1,vw,vh,vmin,vmax是由视窗Viewport大小来决定的,单位1,代表1%,是一种相对单位,只要是为响应式适配视窗的一种解决方案: vw:view width(视窗宽度)的百分比,1vw ...
- 迄今为止最硬核的「Java8时间系统」设计原理与使用方法
为了使本篇文章更容易让读者读懂,我特意写了上一篇<任何人都需要知道的「世界时间系统」构成原理,尤其开发人员>的科普文章.本文才是重点,绝对要读,走起! Java平台时间系统的设计方案 几乎 ...
- 解决 unable to lock the administration directory (/var/lib/dpkg/) 问题
阿里开源镜像站提供了raspbian的软件包镜像,国内的用户可以选择改用阿里镜像站作为更新源. 但是在更换源之后,执行 sudo apt-get update && apt-get u ...
- JavaScript的自调用函数
函数表达式可以 "自调用". 自调用表达式会自动调用. 如果表达式后面紧跟 () ,则会自动调用. 不能自调用声明的函数. 通过添加括号,来说明它是一个函数表达式: <scr ...
- Simulink仿真入门到精通(四) Simulink子系统
4.1 Simulink子系统详解 4.1.1 子系统概述 Simulink根据仿真特性将模块的属性分为两种:虚拟模块和非虚拟模块. 非虚拟模块在仿真过程中起到实际的作用,对其进行编辑或者增加删除操作 ...
- Java 内存模型都不会,就敢在简历上写熟悉并发编程吗
从 PC 内存架构到 Java 内存模型 你知道 Java 内存模型 JMM 吗?那你知道它的三大特性吗? Java 是如何解决指令重排问题的? 既然CPU有缓存一致性协议(MESI),为什么 JMM ...
- Codeforces Round #378 (Div. 2)F
题目:一个带权连通无向图,给第i条边权值减1需要花费ci元,你一共有S元,求最小生成树. 容易得出钱全部花在一条边上是最优的. 我们先做一遍最小生成树. 然后我们枚举减哪一条边. 如果这条边是树上的, ...