C# LINQ学习笔记二:LINQ标准查询操作概述
本笔记摘抄自:https://www.cnblogs.com/liqingwen/p/5801249.html,记录一下学习过程以备后续查用。
“标准查询运算符”是组成语言集成查询 (LINQ) 模式的方法,大多数这些方法都在序列上运行,其中的序列是一个对象,其类型实现了IEnumerable<T>接口
或 IQueryable<T> 接口。标准查询运算符提供了包括筛选、投影、聚合、排序等功能在内的查询功能,各个标准查询运算符在执行时间上有所不同,具体情况
取决于它们是返回单一值还是值序列:
返回单一值的方法(例如Average和Sum)会立即执行,返回序列的方法会延迟查询执行,并返回一个可枚举的对象。
对于在内存中集合上运行的方法(即扩展IEnumerable<T>的方法),返回的可枚举对象将捕获传递到方法的参数。在枚举该对象时,将使用查询运算符的
逻辑,并返回查询结果。与之相反,扩展IQueryable<T>的方法不会实现任何查询行为,但会生成一个表示要执行的查询的表达式树,查询处理由源
IQueryable<T>对象处理。
一、按标准执行方式分类
标准查询运算符方法的LINQ to Objects实现采用两种主要方式之一来执行:立即执行和延迟执行,采用延迟执行的查询运算符可以进一步分为两类:流式和
非流式。
1、执行方式
立即执行:立即执行意味着在代码中声明查询的位置读取数据源并执行运算,返回单个不可枚举的结果的所有标准查询运算符都立即执行。
延迟执行:延迟执行意味着不在代码中声明查询的位置执行运算,仅当对查询变量进行枚举操作时才执行运算,例如通过使用foreach语句,这意味着查询的
执行结果取决于执行查询而非定义查询时的数据源内容。如果多次枚举查询变量,则每次结果可能都不同。几乎所有返回类型为IEnumerable<T>或
IOrderedEnumerable<TElement>的标准查询运算符都以延迟方式执行。
2、延迟执行
流式:运算符不需要在生成元素前读取所有源数据。在执行时,流式运算符一边读取每个源元素,一边对该源元素执行运算,并在可行时生成元素,流式运
算符将持续读取源元素直到可以生成结果元素,这意味着可能要读取多个源元素才能生成一个结果元素。
非流式:运算符必须读取所有源数据才能生成结果元素,诸如排序和分组等运算属于此类别。在执行时,非流式查询运算符读取所有源数据,将其放入数据
结构中,执行运算然后生成结果元素。
二、排列数据
排序操作按一个或多个特性对序列的元素进行排序。第一个排序条件对元素执行主要排序,通过指定第二个排序条件,可以对各个主要排序组中的元素进行
排序。
下图演示对一个字符序列按字母排序操作的执行结果 :
方法名 | 说明 | C# 查询表达式语法 |
OrderBy | 按升序对值进行排序。 | orderby |
OrderByDescending | 按降序对值进行排序。 | orderby … descending |
ThenBy | 按升序执行次要排序。 | orderby …, … |
ThenByDescending | 按降序执行次要排序。 | orderby …, … descending |
Reverse | 颠倒集合中的元素的顺序。 | X |
下面代码演示orderby升序排序:
class Program
{
static void Main(string[] args)
{
#region LINQ orderby升序排序
var words = new[] { "the", "quick", "brown", "fox", "jumps" };
var query =
from word in words
orderby word.Length
select word;
foreach (var word in query)
{
Console.WriteLine(word);
}
Console.Read();
#endregion
}
}
运行结果如下:
下面代码演示orderby降序排序:
class Program
{
static void Main(string[] args)
{
#region LINQ orderby降序排序
var words = new[] { "the", "quick", "brown", "fox", "jumps" };
var query =
from word in words
orderby word.Substring(, ) descending
select word;
foreach (var word in query)
{
Console.WriteLine(word);
}
Console.Read();
#endregion
}
}
运行结果如下:
下面代码演示orderby主要和次要排序(示例一):
class Program
{
static void Main(string[] args)
{
#region LINQ orderby主要和次要排序示例一
var words = new[] { "the", "quick", "brown", "fox", "jumps" };
var query =
from word in words
orderby word.Length, word.Substring(, )
select word;
foreach (var word in query)
{
Console.WriteLine(word);
}
Console.Read();
#endregion
}
}
运行结果如下:
下面代码演示orderby主要和次要排序(示例二):
class Program
{
static void Main(string[] args)
{
#region LINQ orderby主要和次要排序示例二
var words = new[] { "the", "quick", "brown", "fox", "jumps" };
var query =
from word in words
orderby word.Length, word.Substring(, ) descending
select word;
foreach (var word in query)
{
Console.WriteLine(word);
}
Console.Read();
#endregion
}
}
运行结果如下:
三、Set 操作
LINQ中的Set操作是指根据相同或不同集合中是否存在等效元素来生成结果集的查询操作。
方法名 | 说明 |
C# 查询表达式语法 |
Distinct |
从集合移除重复值。 |
X |
Except |
返回差集,差集是指位于一个集合但不位于另一个集合的元素。 |
X |
Intersect |
返回交集,交集是指同时出现在两个集合中的元素。 |
X |
Union |
返回并集,并集是指位于两个集合中任一集合的唯一的元素。 |
X |
图解Set操作
1、Distinct: 返回的序列包含输入序列的唯一元素。
2、Except: 返回的序列只包含位于第一个输入序列但不位于第二个输入序列的元素。
3、Intersect: 返回的序列包含两个输入序列共有的元素。
4、Union: 返回的序列包含两个输入序列的唯一的元素。
四、过滤数据
筛选指将结果集限制为只包含某些满足指定条件的元素的操作,它又称为选择。
下图演示了对字符序列进行筛选的结果,筛选操作的谓词指定字符必须为“A”。
方法名 | 说明 | C# 查询表达式语法 |
OfType | 根据值强制转换为指定类型的能力选择值。 | X |
Where | 选择基于谓词函数的值。 | where |
下面代码演示过滤数据:
class Program
{
static void Main(string[] args)
{
#region LINQ 过滤数据
string[] words = { "the", "quick", "brown", "fox", "jumps" };
var query =
from word in words
where word.Length ==
select word;
foreach (var word in query)
{
Console.WriteLine(word);
}
Console.Read();
#endregion
}
}
运行结果如下:
五、量词操作
限定符运算返回一个Boolean值,该值指示序列中是否有一些元素满足条件或是否所有元素都满足条件。
符“A”,结果为true。
方法名 |
说明 |
C# 查询表达式语法 |
All |
确定是否序列中的所有元素都满足条件。 |
X |
Any |
确定序列中是否有元素满足条件。 |
X |
Contains |
确定序列是否包含指定的元素。 |
X |
六、投影操作
投影是指将对象转换为一种新形式的操作,该形式通常只包含那些将随后使用的属性。通过使用投影,您可以构建依据每个对象生成的新类型,还可以映射
属性,并对该属性执行数学函数,另外还可以在不更改原始对象的情况下映射该对象。
方法名 | 说明 | C# 查询表达式语法 |
Select | 映射基于转换函数的值。 | select |
SelectMany | 映射基于转换函数的值序列,然后将它们展平为一个序列。 | 使用多个 from 子句 |
下面代码演示Select:
class Program
{
static void Main(string[] args)
{
#region LINQ Select
var words = new[] { "the", "quick", "brown", "fox", "jumps" };
var query =
from word in words
select word.Substring(, );
foreach (var word in query)
{
Console.WriteLine(word);
}
Console.Read();
#endregion
}
}
运行结果如下:
下面代码演示SelectMany:
class Program
{
static void Main(string[] args)
{
#region LINQ SelectMany
var phrases = new List<string>() { "an apple a day", "the quick brown fox" };
var query =
from phrase in phrases
from word in phrase.Split(' ')
select word;
foreach (var word in query)
{
Console.WriteLine(word);
}
Console.Read();
#endregion
}
}
运行结果如下:
Select()和SelectMany()的工作都是依据源值生成一个或多个结果值。Select()为每个源值生成一个结果值。因此,总体结果是一个与源集合具有相同元素数
目的集合。与之相反,SelectMany()将生成单一总体结果,其中包含来自每个源值的串联子集合。作为参数传递到SelectMany()的转换函数必须为每个源值返
回一个可枚举值序列,然后,SelectMany() 将串联这些可枚举序列以创建一个大的序列。
下面两个插图演示了这两个方法的操作之间的概念性区别。在每种情况下,假定选择器(转换)函数从每个源值中选择一个由花卉数据组成的数组。
下图描述 Select() 如何返回一个与源集合具有相同元素数目的集合。
下图描述SelectMany()如何将中间数组序列串联为一个最终结果值,其中包含每个中间数组中的每个值。
下面的示例比较Select()和SelectMany()的行为。代码将通过从源集合的每个花卉名称列表中提取前两项来创建一个“花束”。在此示例中,转换函数Select使用
的“单一值”本身就是一个值集合。这需要额外的foreach循环,以便枚举每个子序列中的每个字符串。
/// <summary>
/// 花束类
/// </summary>
class Bouquet
{
public List<string> Flowers { get; set; }
} class Program
{
static void Main(string[] args)
{
#region LINQ Select和SelectMany比较
var bouquets = new List<Bouquet>()
{
new Bouquet {Flowers = new List<string> {"sunflower", "daisy", "daffodil", "larkspur"}},
new Bouquet {Flowers = new List<string> {"tulip", "rose", "orchid"}},
new Bouquet {Flowers = new List<string> {"gladiolis", "lily", "snapdragon", "aster", "protea"}},
new Bouquet {Flowers = new List<string> {"larkspur", "lilac", "iris", "dahlia"}}
}; IEnumerable<List<string>> query1 = bouquets.Select(bq => bq.Flowers);
IEnumerable<string> query2 = bouquets.SelectMany(bq => bq.Flowers); Console.WriteLine("query1->Select():");
foreach (IEnumerable<string> collection in query1)
{
foreach (var item in collection)
{
Console.WriteLine(item);
}
} Console.WriteLine("\nquery2->SelectMany():");
foreach (var item in query2)
{
Console.WriteLine(item);
} Console.Read();
#endregion
}
}
运行结果如下:
七、划分数据
LINQ 中的分区指的是在不重新排列元素的情况下,将输入序列划分为两部分,然后返回其中一个部分的操作。
下图显示对一个字符序列执行三个不同的分区操作的结果。第一个操作返回序列中的前三个元素;第二个操作跳过前三个元素,返回剩余的元素;第三个操作
跳过序列中的前两个元素,返回接下来的三个元素。
运算符名称 |
说明 |
C# 查询表达式语法 |
Skip |
跳过序列中的指定位置之前的元素。 |
X |
SkipWhile |
基于谓词函数跳过元素,直到某元素不再满足条件。 |
X |
Take |
提取序列中的指定位置之前的元素。 |
X |
TakeWhile |
基于谓词函数提取元素,直到某元素不再满足条件。 | X |
八、联接操作
将两个数据源“联接”就是将一个数据源中的对象与另一个数据源中共享某个通用特性的对象关联起来。
当查询所面向的数据源相互之间具有无法直接领会的关系时,联接就成为一项重要的运算。在面向对象的编程中,这可能意味着在未建模对象之间进行关联,
例如对单向关系进行反向推理。
LINQ 框架中提供的联接方法包括Join和GroupJoin。这些方法执行同等联接,即根据两个数据源的键是否相等来匹配这两个数据源的联接。(与此相较,
Transact-SQL支持除“等于”之外的联接运算符,例如“小于”运算符。)用关系数据库术语表达,就是说Join实现了内部联接,这种联接只返回那些在另一个数据集
中具有匹配项的对象。GroupJoin方法在关系数据库术语中没有直接的等效项,但它实现了内部联接和左外部联接的超集。左外部联接是这样一种联接:它返回第
一个(左)数据源的每个元素,即使该元素在另一个数据源中没有关联元素。
下图显示了一个概念性视图,其中包含两个集合以及这两个集合中的包含在内部联接或左外部联接中的元素。
方法名 |
描述 |
C# 查询表达式语法 |
Join |
根据键选择器函数联接两个序列并提取值对。 |
join … in … on … equals … |
GroupJoin |
根据键选择器函数联接两个序列,并对每个元素的结果匹配项进行分组。 |
join … in … on … equals … into … |
九、分组数据
分组指将数据放入组中以便每个组中的元素共享公共特性的操作。
下图显示了对字符序列进行分组的结果,每个组的键是字符。
方法名 |
说明 |
C# 查询表达式语法 |
GroupBy |
对共享公共特性的元素进行分组。 每个组都由一个 IGrouping<TKey, TElement> 对象表示。 |
group … by - 或 - group … by … into … |
ToLookup |
根据键选择器函数将元素插入到 Lookup<TKey, TElement>(一个一对多字典)中。 |
X |
下面代码演示分组数据:
class Program
{
static void Main(string[] args)
{
#region LINQ 分组数据
var numbers = new List<int>() { , , , , , , , , , };
IEnumerable<IGrouping<bool, int>> query = from number in numbers
group number by number % == ;
foreach (var group in query)
{
Console.WriteLine($"{(group.Key ? "偶数" : "基数")}:");
foreach (var item in group)
{
Console.WriteLine(item);
}
}
Console.Read();
#endregion
}
}
运行结果如下:
十、生成操作
生成是指创建新的值序列。
方法名 |
说明 |
C# 查询表达式语法 |
DefaultIfEmpty |
将空集合替换为具有默认值的单一实例集合。 |
X |
Empty |
返回空集合。 |
X |
Range |
生成包含数字序列的集合。 |
X |
Repeat |
生成包含一个重复值的集合。 |
X |
十一、等值操作
如果两个序列的对应元素相等且这两个序列具有相同数量的元素,则视这两个序列相等。
方法名 | 说明 | C# 查询表达式语法 |
SequenceEqual | 通过成对地比较元素确定两个序列是否相等。 | X |
十二、元素操作
元素操作从一个序列返回单个特定元素。
方法名 |
说明 |
C# 查询表达式语法 |
ElementAt |
返回集合中指定索引处的元素。 |
X |
ElementAtOrDefault |
返回集合中指定索引处的元素;如果索引超出范围,则返回默认值。 |
X |
First |
返回集合中的第一个元素或满足条件的第一个元素。 |
X |
FirstOrDefault |
返回集合中的第一个元素或满足条件的第一个元素。如果没有这样的元素,则返回默认值。 |
X |
Last |
返回集合中的最后一个元素或满足条件的最后一个元素。 |
X |
LastOrDefault |
返回集合中的最后一个元素或满足条件的最后一个元素。如果没有这样的元素,则返回默认值。 |
X |
Single |
返回集合中的唯一元素或满足条件的唯一元素。 |
X |
SingleOrDefault |
返回集合中的唯一元素或满足条件的唯一元素。如果没有这样的元素或集合不是正好包含一个元素,则返回默认值。 |
X |
十三、转换数据类型
转换方法更改输入对象的类型。
LINQ查询中的转换运算可用于各种应用程序,下面是一些示例:
1、Enumerable.AsEnumerable<TSource> 方法可用于隐藏类型的标准查询运算符的自定义实现。
2、Enumerable.OfType<TResult> 方法可用于启用非参数化集合以进行LINQ查询。
3、Enumerable.ToArray<TSource>、Enumerable.ToDictionary<TSource, TKey>、Enumerable.ToList<TSource> 和 Enumerable.ToLookup<TSource, TKey>
方法可用于强制立即执行查询,而非推迟到枚举查询时。
方法名 | 说明 | C# 查询表达式语法 |
AsEnumerable | 返回类型为 IEnumerable<T> 的输入。 | X |
AsQueryable | 将(泛型)IEnumerable 转换为(泛型)IQueryable。 | X |
Cast | 将集合的元素强制转换为指定类型。 |
使用显式类型化的范围变量。 例如: from string str in words |
OfType | 根据值强制转换为指定类型的能力筛选值。 | X |
ToArray | 将集合转换为数组。 此方法强制执行查询。 | X |
ToDictionary | 根据键选择器函数将元素放入 Dictionary<TKey, TValue> 中。 此方法强制执行查询。 | X |
ToList | 将集合转换为 List<T>。 此方法强制执行查询。 | X |
ToLookup | 根据键选择器函数将元素放入 Lookup<TKey, TElement>(一对多字典)中。 此方法强制执行查询。 | X |
下面代码演示转换数据类型:
/// <summary>
/// 植物类
/// </summary>
class Plant
{
public string Name { get; set; }
} /// <summary>
/// 食肉植物类
/// </summary>
class CarnivorousPlant : Plant
{
public string TrapType { get; set; }
} class Program
{
static void Main(string[] args)
{
#region LINQ 转换数据类型
var plants = new Plant[]
{
new CarnivorousPlant {Name = "Venus Fly Trap", TrapType = "Snap Trap"},
new CarnivorousPlant {Name = "Pitcher Plant", TrapType = "Pitfall Trap"},
new CarnivorousPlant {Name = "Sundew", TrapType = "Flypaper Trap"},
new CarnivorousPlant {Name = "Waterwheel Plant", TrapType = "Snap Trap"}
};
var query = from CarnivorousPlant plant in plants
where plant.TrapType == "Snap Trap"
select plant;
foreach (var carnivorousPlant in query)
{
Console.WriteLine(carnivorousPlant.Name);
}
Console.Read();
#endregion
}
}
运行结果如下:
十四、串联操作
串联是指将一个序列追加到另一个序列的运算。
下图演示对两个字符序列执行的串联运算。
方法名 |
说明 |
C# 查询表达式语法 |
Concat |
串联两个序列以组成一个序列。 |
X |
十五、聚合操作
聚合运算从值集合计算单个值。从一个月的日温度值计算日平均温度就是聚合运算的一个示例。
下图显示了对一个数字序列执行两个不同聚合运算的结果。第一个运算对这些数字执行求和;第二个运算返回该序列中的最大值。
方法名 |
说明 |
C# 查询表达式语法 |
Aggregate |
对集合值执行自定义聚合运算。 |
X |
Average |
计算值集合的平均值。 |
X |
Count |
对集合中的元素进行计数,还可以仅对满足某一谓词函数的元素进行计数。 |
X |
LongCount |
对大型集合中的元素进行计数,还可以仅对满足某一谓词函数的元素进行计数。 |
X |
Max |
确定集合中的最大值。 |
X |
Min |
确定集合中的最小值。 |
X |
Sum |
计算集合中值的总和。 |
X |
C# LINQ学习笔记二:LINQ标准查询操作概述的更多相关文章
- [C#] 进阶 - LINQ 标准查询操作概述
LINQ 标准查询操作概述 序 “标准查询运算符”是组成语言集成查询 (LINQ) 模式的方法.大多数这些方法都在序列上运行,其中的序列是一个对象,其类型实现了IEnumerable<T> ...
- [Spring Data MongoDB]学习笔记--MongoTemplate查询操作
查询操作主要用到两个类:Query, Criteria 所有的find方法都需要一个query的object. 1. 直接通过json来查找,不过这种方式在代码中是不推荐的. BasicQuery q ...
- jquery学习笔记(二):DOM元素操作
内容来自[汇智网]jquery学习课程 2.1 元素属性操作 1.获取元素的属性 语法:attr(name) 参数name表示属性的名称 2.设置元素的属性 单个属性设置语法:attr(key,val ...
- jQuery学习笔记(二)jQuery中DOM操作
目录 DOM操作分类 jQuery中的各种DOM操作 查找节点 创建节点 删除节点 复制节点 替换节点 包裹节点 属性操作 样式操作 对HTML.文本和值的操作 遍历节点 CSS-DOM操作 小结 本 ...
- python学习笔记(二)---for循环与操作列表
内容概要 for循环 range(start,end,step)函数 生成随机数列表 list()函数 将range()的结果整合到某个列表 列表的操作 切片(start: end :step) 元组 ...
- 微信小程序学习笔记二 数据绑定 + 事件绑定
微信小程序学习笔记二 1. 小程序特点概述 没有DOM 组件化开发: 具备特定功能效果的代码集合 体积小, 单个压缩包体积不能大于2M, 否则无法上线 小程序的四个重要的文件 *js *.wxml - ...
- LINQ入门教程之各种标准查询操作符(二)
续上篇LINQ入门教程之各种标准查询操作符(一) LINQ入门教程之各种标准查询操作符(二) 7. 聚合操作符 8. 集合操作符 9. 生成操作符 #region 生成操作符 即从现有序列的值中 ...
- LINQ入门教程之各种标准查询操作符(一)
好久之前就想系统的学习下LINQ,好久之前…… 本篇文章主要介绍LINQ等的标准查询操作符,内容取自<LINQ高级编程>,后续还会介绍LINQ to XML ,LINQ to SQL. L ...
- AJax 学习笔记二(onreadystatechange的作用)
AJax 学习笔记二(onreadystatechange的作用) 当发送一个请求后,客户端无法确定什么时候会完成这个请求,所以需要用事件机制来捕获请求的状态XMLHttpRequest对象提供了on ...
随机推荐
- #614 C. NEKO's Maze Game[简易DFS,0|1转换]
起初一直看不懂题的意思,最后看了大佬的视频讲解才明白了题的意思. 题意:每次询问重复的时候抵消上一次操作 如果是奇数次的操作则视为障碍阻挡前进 收获:0和1的转换技巧,简单搜索和巧定义全局变量,没必 ...
- ID生成器之——别人家的方案and自家的方案
“叮咚,叮咚……”,微信提示音一声接一声,声音是那么的频繁,有妖气,待俺去看一看. 这天刚吃完午饭,打开微信,发现我们的技术讨论组里有 100 多条未读消息,心想,是不是系统出问题了?怎么消息那么频繁 ...
- 图解Java设计模式之UML类图
图解Java设计模式之UML类图 3.1 UML基本介绍 UML图 UML类图 3.1 UML基本介绍 1)UML – Unified modeling language UML(统一建模语言),是一 ...
- C# 调用WCF服务的两种方法
项目简介 之前领导布置一个做单点登录的功能给我,实际上就是医院想做一个统一的平台来实现在这个统一的平台登录后不需要在His.Emr.Lis等系统一个个登录,直接可以登录到对应的系统,然后进行相应的操作 ...
- #《Essential C++》读书笔记# 第一章 C++ 编程基础
前言 Stanley B.Lippman 先生所著的<C++ Primer>是学习C++的一本非常优秀的教科书,但<C++ Primer>作为一本大部头书,显然不适合所有的初学 ...
- vue自定义分页组件---切图网
vue2.5自定义分页组件 Pagination.vue,可设置每页显示条数,带跳转框直接跳转到相应页面,亲测有用.目前很多框架自带有分页组件比如elementUI,不过在面对一个拿到PSD稿,然后重 ...
- 记录zabbix4.0升级4.2
系统环境 [root@localhost ~]# cat /etc/redhat-release CentOS release 6.9 (Final) 官方网站 官方文档升级其实很简单如果 ...
- 【Java】基于RXTX的Java串口通信
本篇内容参考转载自https://blog.csdn.net/kong_gu_you_lan/article/details/80589859 环境搭建 下载地址:http://fizzed.com/ ...
- MySQL表名大小写敏感性
Linux版MySQL 库名与表名是严格区分大小写的: 表的别名是严格区分大小写的: 列名与列的别名在所有的情况下均是忽略大小写的: 变量名也是严格区分大小写的: 修改步骤如下: 1. 编辑[/etc ...
- js增删class的方法
接下来我来介绍两种方法 我们先来一段HTMl代码 <div id="bb"> 你好呀 </div> 接下来我们再来一段css样式 .ob { color:r ...