LINQ标准查询操作概述

原创
小哥 3年前 (2023-05-22) 阅读数 222 #大杂烩

转自:http://www.cnblogs.com/liqingwen/p/5801249.html

序

“标准查询运算符”是语言集成查询的一个组件 (LINQ) 图案的方法。这些方法中的大多数都在序列上运行,其中序列是其类型实现的对象 IEnumerable 接口或 IQueryable 接口。标准查询运算符提供 过滤、投影、聚合、排序 查询功能包括其他功能。

每个标准查询运算符都位于 执行时间 根据他们是否返回而有所不同 单一值 还是 值序列 。返回单个值的方法(例如 Average 和 Sum )会 立即执行 。返回序列的方法将 延迟查询执行 并返回一个可枚举的对象。

对于在内存中的集合(即扩展)上运行的方法 IEnumerable 返回的可枚举对象将捕获传递给该方法的参数。枚举此对象时,将使用查询运算符的逻辑并返回查询结果。

与之相反 ,扩展 IQueryable 的方法 不会实现任何查询行为 ,但 会生成 表示要执行的查询的查询 表达式树 。按源进行查询处理 IQueryable 对象处理。

一、按标准执行方式分类

标准查询运算符方法 LINQ to Objects 实施以两种主要方式之一进行: 立即执行 和 延迟执行 。使用延迟执行的查询运算符可以进一步分为两类: 流式 和 非流式 。

1.执行方式

(1) 立即 : 立即执行意味着读取数据源并在代码中声明查询的位置执行操作。 返回单个非枚举结果的所有标准查询运算符将立即执行 。

(2) 延迟 : 延迟执行意味着不会在代码中声明查询的位置执行操作。 该操作仅在枚举查询变量时执行, 例如,通过使用 foreach 句。这意味着查询的执行结果 取决于执行查询 而不是在查询时定义数据源内容。如果多次枚举查询变量,则每次的结果可能会有所不同。几乎所有返回类型都是 IEnumerable 或 IOrderedEnumerable 所有标准查询运算符都以延迟方式执行。

使用延迟执行的查询运算符可以进一步分类为 流式 和 非流式 。

① 流运算符在生成元素之前不需要读取所有源数据 。在执行过程中,流运算符在对源元素执行操作时读取每个源元素,并在可行时生成元素。流式处理运算符将继续读取源元素,直到可以生成结果元素。这意味着可能需要读取多个源元素才能生成单个结果元素。

② 非流式处理运算符必须读取所有源数据才能生成结果元素 。诸如 排序 和 分组 相等操作属于此类别。在执行时,非流式查询运算符读取所有源数据,将其放置在数据结构中,执行操作,然后生成结果元素。

2、 整理数据

排序操作根据一个或多个特征对序列的元素进行排序。第一个排序条件对元素执行主要排序。通过指定第二个排序条件,可以对每个主排序组中的元素进行排序。

下图演示了对字符序列执行按字母顺序排序操作的结果。

标准查询运算符操作方法 - 排序

方法名

说明

C# 查询表达式语法

OrderBy

按升序对值进行排序。

orderby

OrderByDescending

按降序对值进行排序。

orderby … descending

ThenBy

按升序执行二次排序。

orderby …, …

ThenByDescending

按降序执行二次排序。

orderby …, … descending

Reverse

反转集合中元素的顺序。

X

示例:

1 var words = new[] { "the", "quick", "brown", "fox", "jumps" }; 2 var query = from word in words 3 orderby word.Length 4 select word; 5 6 foreach (var word in query) 7 { 8 Console.WriteLine(word); 9 }

1 var words = new[] { "the", "quick", "brown", "fox", "jumps" }; 2 var query = from word in words 3 orderby word.Substring(0,1) descending 4 select word; 5 6 foreach (var word in query) 7 { 8 Console.WriteLine(word); 9 }

1 var words = new[] { "the", "quick", "brown", "fox", "jumps" }; 2 var query = from word in words 3 orderby word.Length, word.Substring(0, 1) 4 select word; 5 6 foreach (var word in query) 7 { 8 Console.WriteLine(word); 9 }

1 var words = new[] { "the", "quick", "brown", "fox", "jumps" }; 2 var query = from word in words 3 orderby word.Length, word.Substring(0, 1) descending 4 select word; 5 6 foreach (var word in query) 7 { 8 Console.WriteLine(word); 9 }

三、Set 操作

LINQ 中的 Set 操作是指基于相同或不同的操作 集合 中是否有等效元素来生成结果集 查询操作 。

标准查询运算符操作方法 - Set

方法名

说明

C# 查询表达式语法

Distinct

从集合中删除重复值。

X

Except

返回差值集,该差值集引用位于一个集中但不在另一个集中的元素。

X

Intersect

返回交集,该交集引用在两集中同时出现的元素。

X

Union

返回一个联合,该联合引用位于两个集合的任一集中的唯一元素。

X

图解 Set 操作

(1)Distinct: 返回的序列包含输入序列的唯一元素。

(2)Except: 返回的序列仅包含位于第一个输入序列中的元素,而不包含位于第二个输入序列中的元素。

(3)Intersect: 返回的序列包含两个输入序列共有的元素。

(4)Union: 返回的序列包含两个输入序列的唯一元素。

4、 筛选数据

筛选 指将结果集限制为仅包含满足指定条件的某些元素的操作。它也被称为 选择 。

下图说明了筛选字符序列的结果。筛选器操作的谓词指定字符必须是”A”。

标准查询运算符操作方法 - 筛选

方法名

说明

C# 查询表达式语法

OfType

根据将其强制转换为指定类型的功能选择一个值。

X

Where

根据谓词函数选择值。

where

示例:

1 string[] words = { "the", "quick", "brown", "fox", "jumps" }; 2 3 var query = from word in words 4 where word.Length == 3 5 select word; 6 7 foreach (var word in query) 8 { 9 Console.WriteLine(word); 10 }

五、量词运算

限定符操作返回 Boolean 指示序列中的某些元素是否满足条件或是否所有元素都满足条件的值。

下图描述了对同一来源的两个不同序列的两种不同的限定符操作。第一个操作询问一个或多个元素是否为字符”A“结果是 true 。第二个操作询问是否所有元素都是字符”A“结果是 true 。

标准查询运算符操作方法 - 量词

方法名

说明

C# 查询表达式语法

All

确定序列中的所有元素是否都满足条件。

X

Any

确定序列中是否有任何元素满足条件。

X

Contains

确定序列是否包含指定的元素。

X

六、投影操作

投影是指将对象转换为新形式的操作,通常仅包括稍后将使用的那些属性。通过使用投影,可以生成基于每个对象生成的新类型。您可以映射属性并对其执行数学函数。您还可以在不更改原始对象的情况下映射原始对象。

标准查询运算符操作方法 - 投影

方法名

说明

C# 查询表达式语法

Select

基于转换函数映射值。

select

SelectMany

根据转换函数映射值序列,然后将其平展为序列。

使用多个 from 子句

示例

1 var words = new[] { "the", "quick", "brown", "fox", "jumps" }; 2 var query = from word in words 3 select word.Substring(0,1); 4 5 foreach (var word in query) 6 { 7 Console.WriteLine(word); 8 }

1 var phrases = new List() { "an apple a day", "the quick brown fox" }; 2 3 var query = from phrase in phrases 4 from word in phrase.Split( ) 5 select word; 6 7 foreach (var word in query) 8 { 9 Console.WriteLine(word); 10 }

Select() 和 SelectMany() 我们的工作是根据源值生成一个或多个结果值。 Select() 为 为每个源值生成结果值 。因此, 总体结果是一个与源集具有相同数量元素的集合 。相反, SelectMany() 将生成 单一总体结果 ,其中包括来自 每个源值的串联子集 。作为参数传递给 SelectMany() 的转换函数必须为每个源值返回可枚举的值序列。然后 SelectMany() 这些可枚举序列将连接起来以创建一个大型序列。

以下两个插图演示了这两种方法的操作之间的概念差异。在每种情况下,假设选择器(转换)函数从每个源值中选择一个由花朵数据组成的数组。

下图描述 Select() 如何返回与源集具有相同元素数的集合。

下图描述 SelectMany() 如何将中间数组序列连接到包含每个中间数组中每个值的最终结果值。

示例

以下示例比较 Select() 和 SelectMany() 做。该代码将通过从源集合中的每个花名称列表中提取前两项来创建“花束”。在此示例中,转换函数 Select 使用的“ 单一值 “它本身就是一套价值观。这需要额外的 foreach 循环以枚举每个子序列中的每个字符串。

1 static void Main(string[] args) 2 { 3 var bouquets = new List() 4 { 5 new Bouquet {Flowers = new List {"sunflower", "daisy", "daffodil", "larkspur"}}, 6 new Bouquet {Flowers = new List {"tulip", "rose", "orchid"}}, 7 new Bouquet {Flowers = new List {"gladiolis", "lily", "snapdragon", "aster", "protea"}}, 8 new Bouquet {Flowers = new List {"larkspur", "lilac", "iris", "dahlia"}} 9 }; 10 11 IEnumerable<List> query1 = bouquets.Select(bq => bq.Flowers); 12 IEnumerable query2 = bouquets.SelectMany(bq => bq.Flowers); 13 14 Console.WriteLine("query1 - Select():"); 15 foreach (IEnumerable collection in query1) 16 { 17 foreach (var item in collection) 18 { 19 Console.WriteLine(item); 20 } 21 } 22 23 Console.WriteLine("\nquery2 - SelectMany():"); 24 foreach (var item in query2) 25 { 26 Console.WriteLine(item); 27 } 28 29 Console.Read(); 30 } 31 32 class Bouquet 33 { 34 public List Flowers { get; set; } 35 }

7、 分区数据

LINQ 中的分区是指 不要重新排列元素 在这种情况下,将输入序列分成两部分,然后返回操作的一部分。

下图显示了对字符序列执行三种不同分区操作的结果。第一个操作返回序列中的前三个元素。第二个操作跳过前三个元素并返回其余元素。第三个操作跳过序列中的前两个元素,并返回接下来的三个元素。

分区序列的标准查询运算符方法

操作员名称

说明

C# 查询表达式语法

Skip

跳过序列中指定位置之前的元素。

X

SkipWhile

跳过基于谓词函数的元素,直到元素不再满足条件。

X

Take

提取序列中指定位置之前的元素。

X

TakeWhile

基于谓词函数提取元素,直到某个元素不再满足条件。

X

八、加盟操作

合并两个数据源 “联接” 它是将一个数据源中的对象与另一个数据源中共享公共属性的对象相关联。

当查询所针对的数据源具有无法直接理解的关系时,联接将成为一项重要操作。在面向对象的编程中,这可能意味着未建模对象之间的关联,例如单向关系的反向推理。下面是单向关系的示例:Customer 类具有 City 的属性,但是 City 类不充当 Customer 对象集合的属性。如果您有 City 对象列表,并且要查找每个城市中的所有客户,可以使用联接操作来完成此搜索。

LINQ 框架中提供的连接方法包括 Join 和 GroupJoin 。这些方法执行相等联接,这些联接根据两个数据源的键是否相等来匹配这两个数据源的联接。与此相比,Transact-SQL 支持“等于”以外的连接运算符,例如“小于”运算符 就关系数据库术语而言,这意味着 Join 实现了仅返回在另一个数据集中具有匹配项的对象的内部联接。 GroupJoin 该方法在关系数据库术语中没有直接等效项,但它实现了内联接和左外联接的超集。左外联接是返回第一个(左)数据源的每个元素的联接,即使该元素在另一个数据源中没有关联的元素也是如此。

下图显示了一个概念视图,其中包含两个集合以及这两个集合中的内联接或左外联接中包含的元素。

标准查询运算符操作方法 - 联接

方法名

描述

C# 查询表达式语法

Join

连接两个序列并根据键选择器功能提取值对。

join … in … on … equals …

GroupJoin

根据键选择器功能连接两个序列,并对每个元素的结果匹配进行分组。

join … in … on … equals … into …

9、 分组数据

分组是指将数据放入组中的操作,以便每个组中的元素具有共同的特征。

下图显示了对字符序列进行分组的结果。每个组的 键 是字符。

标准查询运算符方法 - 分组

方法名

说明

C# 查询表达式语法

GroupBy

对具有共同要素的元素进行分组。 每个组由 IGrouping <TKey, TElement> 对象表示。

group … by

  • 或 -

group … by … into …

ToLookup

将元素插入到 Lookup <TKey, TElement> (一对多字典)。

X

1 var numbers = new List() { 35, 44, 200, 84, 3987, 4, 199, 329, 446, 208 }; 2 3 IEnumerable<IGrouping<bool, int>> query = from number in numbers 4 group number by number % 2 == 0; 5 6 foreach (var group in query) 7 { 8 Console.WriteLine($"{(group.Key ? "偶数" : "基数")}:"); 9 foreach (var i in group) 10 { 11 Console.WriteLine(i); 12 } 13 }

10、 生成操作

生成是指 创建新的值序列 。

标准查询运算符方法 - 生成

方法名

说明

C# 查询表达式语法

DefaultIfEmpty

将空集合替换为具有默认值的单个实例集合。

X

Empty

返回一个空集合。

X

Range

生成包含数字序列的集合。

X

Repeat

生成包含重复值的集合。

X

11、等效运算

如果两个序列的相应元素相等并且它们具有相同数量的元素,则这两个序列被视为相等。

标准查询运算符方法 - 等值

方法名

说明

C# 查询表达式语法

SequenceEqual

通过比较成对的元素来确定两个序列是否相等。

X

12、 元件操作

元素操作从序列返回 单个特定元素 。

标准查询运算符操作方法 - 元素

方法名

说明

C# 查询表达式语法

ElementAt

返回集合中指定索引处的元素。

X

ElementAtOrDefault

返回集合中指定索引处的元素;如果索引超出范围,则返回默认值。

X

First

返回集合中的第一个元素或满足条件的第一个元素。

X

FirstOrDefault

返回集合中的第一个元素或满足条件的第一个元素。 如果没有此类元素,则返回默认值。

X

Last

返回集合中的最后一个元素或满足条件的最后一个元素。

X

LastOrDefault

返回集合中的最后一个元素或满足条件的最后一个元素。 如果没有此类元素,则返回默认值。

X

Single

返回集合中的唯一元素或满足条件的唯一元素。

X

SingleOrDefault

返回集合中的唯一元素或满足条件的唯一元素。 如果没有此类元素,或者集合不完全包含一个元素,则返回默认值。

X

13、 移位条款

转换方法 更改输入对象的类型 。

LINQ 查询中的转换操作可用于各种应用程序。以下是一些示例:

(1) Enumerable .AsEnumerable 方法可用于自定义隐藏类型的标准查询运算符的实现。

(2) Enumerable .OfType 方法可用于启用非参数化集合 LINQ 查询。

(3) Enumerable .ToArray 、 Enumerable .ToDictionary <TSource, TKey> 、 Enumerable .ToList 和 Enumerable .ToLookup <TSource, TKey> 方法可用于强制立即执行查询,而不是延迟到枚举查询时间。

标准查询运算符方法 - 移位条款

方法名

说明

C# 查询表达式语法

AsEnumerable

返回类型为 IEnumerable 的输入。

X

AsQueryable

意志(通用) IEnumerable 转换为(通用) IQueryable 。

X

Cast

将集合的元素强制转换为指定类型。

使用显式类型化的作用域变量。 例如:

from string str in words

OfType

根据将值强制转换为指定类型的能力筛选值。

X

ToArray

将集合转换为数组。 此方法强制执行查询。

X

ToDictionary

将元素放入按键选择器功能 Dictionary <TKey, TValue> 中。 此方法强制执行查询。

X

ToList

将集合转换为 List 。 此方法强制执行查询。

X

ToLookup

将元素放入按键选择器功能 Lookup <TKey, TElement> (一对多词典)。 此方法强制执行查询。

X

示例:

1 static void Main(string[] args) 2 { 3 var plants = new Plant[] 4 { 5 new CarnivorousPlant {Name = "Venus Fly Trap", TrapType = "Snap Trap"}, 6 new CarnivorousPlant {Name = "Pitcher Plant", TrapType = "Pitfall Trap"}, 7 new CarnivorousPlant {Name = "Sundew", TrapType = "Flypaper Trap"}, 8 new CarnivorousPlant {Name = "Waterwheel Plant", TrapType = "Snap Trap"} 9 }; 10 11 var query = from CarnivorousPlant plant in plants 12 where plant.TrapType == "Snap Trap" 13 select plant; 14 15 foreach (var carnivorousPlant in query) 16 { 17 Console.WriteLine(carnivorousPlant.Name); 18 } 19 20 Console.Read(); 21 } 22 23 class Plant 24 { 25 public string Name { get; set; } 26 } 27 28 class CarnivorousPlant : Plant 29 { 30 public string TrapType { get; set; } 31 }

14、串联操作

串联是指组合序列 追加 对另一个序列的操作。

下图演示了对两个字符序列执行的串联操作。

标准查询运算符操作方法 - 串联

方法名

说明

C# 查询表达式语法

Concat

连接两个序列以形成一个序列。

X

15、聚合操作

值集的聚合操作 计算单个值 。根据一个月的每日温度值计算日平均温度是聚合操作的一个示例。

下图显示了对数字序列执行两个不同聚合操作的结果。第一个操作对这些数字执行求和。第二个操作返回序列中的最大值。

标准查询运算符操作方法 - 聚合

方法名

说明

C# 查询表达式语法

Aggregate

对设置值执行自定义聚合操作。

X

Average

计算一组值的平均值。

X

Count

对集合中的元素进行计数,也可以只计算满足某个谓词函数的元素。

X

LongCount

对大型集合中的元素进行计数也只能对满足特定谓词函数的元素进行。

X

Max

确定集合中的最大值。

X

Min

确定集合中的最小值。

X

Sum

计算集合中值的总和。

X

传送门

入门:《 走进 LINQ 的世界 》

进阶:《 LINQ 标准查询操作概述 》 (强烈推荐)

技巧:《 Linq To Objects - 如何操作字符串 》 和 《 Linq To Objects - 如何操作文件目录 》


【参考】https://msdn.microsoft.com/zh-cn/library/bb397896(v=vs.100).aspx

[来源]部分图片摘自微软官方文档

版权声明

所有资源都来源于爬虫采集,如有侵权请联系我们,我们将立即删除