LINQ 标准查询操作概述

  “标准查询运算符”是组成语言集成查询 (LINQ) 模式的方法。大多数这些方法都在序列上运行,其中的序列是一个对象,其类型实现了IEnumerable<T> 接口或 IQueryable<T> 接口。标准查询运算符提供了包括筛选、投影、聚合、排序等功能在内的查询功能。  
     各个标准查询运算符在执行时间上有所不同,具体情况取决于它们是返回单一值还是值序列。返回单一值的方法(例如 Average 和 Sum)会立即执行。返回序列的方法会延迟查询执行,并返回一个可枚举的对象。  
     对于在内存中集合上运行的方法(即扩展 IEnumerable<T> 的方法),返回的可枚举对象将捕获传递到方法的参数。在枚举该对象时,将使用查询运算符的逻辑,并返回查询结果。  
     与之相反,扩展 IQueryable<T> 的方法不会实现任何查询行为,但会生成一个表示要执行的查询的表达式树。查询处理由源 IQueryable<T> 对象处理。
 

一、按标准执行方式分类

     标准查询运算符方法的 LINQ to Objects 实现采用两种主要方式之一来执行:立即执行和延迟执行。采用延迟执行的查询运算符可以进一步分为两类:流式和非流式。
     
     1.执行方式
          (1)立即: 立即执行意味着在代码中声明查询的位置读取数据源并执行运算。  返回单个不可枚举的结果的所有标准查询运算符都立即执行。
          (2)延迟: 延迟执行意味着不在代码中声明查询的位置执行运算。  仅当对查询变量进行枚举操作时才执行运算,例如通过使用 foreach 语句。这意味着查询的执行结果取决于执行查询而非定义查询时的数据源内容。如果多次枚举查询变量,则每次结果可能都不同。几乎所有返回类型为 IEnumerable<T> 或 IOrderedEnumerable<TElement> 的标准查询运算符都以延迟方式执行。 
           采用延迟执行方式的查询运算符可以另外分类为流式和非流式。
          ①流式运算符不需要在生成元素前读取所有源数据。在执行时,流式运算符一边读取每个源元素,一边对该源元素执行运算,并在可行时生成元素。流式运算符将持续读取源元素直到可以生成结果元素。这意味着可能要读取多个源元素才能生成一个结果元素。
          ②非流式运算符必须读取所有源数据才能生成结果元素。诸如排序和分组等运算属于此类别。在执行时,非流式查询运算符读取所有源数据,将其放入数据结构中,执行运算,然后生成结果元素。
 

二、排列数据

     排序操作按一个或多个特性对序列的元素进行排序。第一个排序条件对元素执行主要排序。通过指定第二个排序条件,可以对各个主要排序组中的元素进行排序。 
     下图演示对一个字符序列执行按字母排序操作的结果。
  
标准查询运算符操作方法 - 排序
方法名 说明 C# 查询表达式语法
OrderBy 按升序对值进行排序。 orderby
OrderByDescending 按降序对值进行排序。 orderby … descending
ThenBy 按升序执行次要排序。 orderby …, …
ThenByDescending 按降序执行次要排序。 orderby …, … descending
Reverse 颠倒集合中的元素的顺序。 X

  

  示例:

 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);
}

下面通过演示使用 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);
}

下面通过演示使用 orderby descending 进行降序排序:按字符串的第一个字母

 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);
}

下面通过演示使用 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);
}

下面通过演示使用 orderby descending 进行主要和次要排序:先升序按字符串长度(主)、再降序按字符串的第一个字母(次)

三、Set 操作

  LINQ 中的 Set 操作是指根据相同或不同集合中是否存在等效元素来生成结果集的查询操作。

标准查询运算符操作方法 - 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

  

  示例:
 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);
}

使用 where 子句来从数组中筛选那些具有特定长度的字符串

五、量词操作

  限定符运算返回一个 Boolean 值,该值指示序列中是否有一些元素满足条件或是否所有元素都满足条件。

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

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

方法名

说明

C# 查询表达式语法

All

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

X
Any

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

X

Contains

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

X

六、投影操作

      投影是指将对象转换为一种新形式的操作,该形式通常只包含那些将随后使用的属性。通过使用投影,您可以构建依据每个对象生成的新类型。您可以映射属性,并对该属性执行数学函数。还可以在不更改原始对象的情况下映射该对象。
 
标准查询运算符操作方法 - 投影
方法名 说明 C# 查询表达式语法
Select 映射基于转换函数的值。 select
SelectMany 映射基于转换函数的值序列,然后将它们展平为一个序列。 使用多个 from 子句

  

  示例

 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);
}

Select:下面的示例使用 select 子句来映射字符串列表中每个字符串的第一个字母

 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);
}

SelectMany:下面的示例使用多个 from 子句来映射字符串列表中每个字符串中的每个单词

  

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

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

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

  下图描述 SelectMany() 如何将中间数组序列串联为一个最终结果值,其中包含每个中间数组中的每个值。

  示例

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

         static void Main(string[] args)
{
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();
} class Bouquet
{
public List<string> Flowers { get; set; }
}

七、划分数据

  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 …

九、分组数据

  分组指将数据放入组中以便每个组中的元素共享公共特性的操作。
  下图显示了对字符序列进行分组的结果。每个组的键是字符。  

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

方法名

说明

C# 查询表达式语法

GroupBy

对共享公共特性的元素进行分组。  每个组都由一个 IGrouping<TKey, TElement> 对象表示。

group … by

- 或 -

group … by … into …

ToLookup

根据键选择器函数将元素插入到 Lookup<TKey, TElement>(一个一对多字典)中。

X
 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 i in group)
{
Console.WriteLine(i);
}
}

使用 group by 子句根据列表中的整数是奇数还是偶数进行分组

十、生成操作

  生成是指创建新的值序列。
 
标准查询运算符方法 - 生成

方法名

说明

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

  

  示例:

         static void Main(string[] args)
{
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();
} class Plant
{
public string Name { get; set; }
} class CarnivorousPlant : Plant
{
public string TrapType { get; set; }
}

使用显式类型化的范围变量将类型强制转换为子类型,然后才访问仅在此子类型中提供的成员。

十四、串联操作

  串联是指将一个序列追加到另一个序列的运算。

  下图演示对两个字符序列执行的串联运算。

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

方法名

说明

C# 查询表达式语法

Concat

串联两个序列以组成一个序列。

X

十五、聚合操作

  聚合运算从值集合计算单个值。从一个月的日温度值计算日平均温度就是聚合运算的一个示例。

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

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

方法名

说明

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

【来源】部分图片摘自微软官方文档

[C#] 进阶 - LINQ 标准查询操作概述的更多相关文章

  1. C# LINQ学习笔记二:LINQ标准查询操作概述

    本笔记摘抄自:https://www.cnblogs.com/liqingwen/p/5801249.html,记录一下学习过程以备后续查用. “标准查询运算符”是组成语言集成查询 (LINQ) 模式 ...

  2. C#3.0新增功能09 LINQ 标准查询运算符 04 运算

    连载目录    [已更新最新开发文章,点击查看详细] 本篇主要介绍标准查询运算符的常用运算功能. 01 对数据排序 排序操作基于一个或多个属性对序列的元素进行排序. 第一个排序条件对元素执行主要排序. ...

  3. C#3.0新增功能09 LINQ 标准查询运算符 01 概述

    连载目录    [已更新最新开发文章,点击查看详细] 标准查询运算符 是组成 LINQ 模式的方法. 这些方法中的大多数都作用于序列:其中序列指其类型实现 IEnumerable<T> 接 ...

  4. .NET LINQ标准查询运算符

    标准查询运算符概述      “标准查询运算符”是组成语言集成查询 (LINQ) 模式的方法. 大多数这些方法都在序列上运行,其中的序列是一个对象,其类型实现了 IEnumerable<T> ...

  5. Linq 标准查询操作符三

    本文介绍了LINQ标准查询操作符.没有这些操作符,LINQ就不会存在.本文为理解这些操作符的功能提供了很好的基础.了解它们将会很有帮助,因为LINQ的各种Provider都是基于这些操作符来完成各自丰 ...

  6. LINQ 标准查询操作符

    本文介绍了LINQ标准查询操作符.没有这些操作符,LINQ就不会存在.本文为理解这些操作符的功能提供了很好的基础.了解它们将会很有帮助,因为LINQ的各种Provider都是基于这些操作符来完成各自丰 ...

  7. LINQ标准查询运算符的执行方式-延时之流式处理

    linq的延时执行是指枚举时才去一个个生成结果元素. 流式处理是linq延时执行的一种,在生成元素前不需要获取所有源元素,只要获取到的源元素足够计算时,便生成结果元素. 流式处理的标准查询运算符返回值 ...

  8. LINQ标准查询操作符详解(转)

     一. 关于LINQ       LINQ 英文全称是“Language-Integrated Query”,中文为“语言集成查询”,它是微软首席架构师.Delphi 之父和C# 之父——Anders ...

  9. 【LINQ标准查询操作符总结】之聚合操符

    C#  中的LINQ 提供了两种操作方式,查询表达式和查询操作符,所有的查询表达式都有对应的查操作符类替代,查询表达式有点“类” SQL,在代码中写SQL,总觉得不够“优雅”,使用查询操作符就显得“优 ...

随机推荐

  1. 日期格式代码出现两次的错误 ORA-01810

    错误的原因是使用了两次MM . 一.Oracle中使用to_date()时格式化日期需要注意格式码 如:select to_date('2005-01-01 11:11:21','yyyy-MM-dd ...

  2. ABP文档 - Javascript Api - AJAX

    本节内容: AJAX操作相关问题 ABP的方式 AJAX 返回信息 处理错误 HTTP 状态码 WrapResult和DontWrapResult特性 Asp.net Mvc 控制器 Asp.net ...

  3. ExtJS 4.2 组件介绍

    目录 1. 介绍 1.1 说明 1.2 组件分类 1.3 组件名称 1.4 组件结构 2. 组件的创建方式 2.1 Ext.create()创建 2.2 xtype创建 1. 介绍 1.1 说明 Ex ...

  4. Modify Branding of FreeCAD

    Modify Branding of FreeCAD eryar@163.com This article describes the Branding of FreeCAD. Branding me ...

  5. SQL Server-聚焦NOT IN VS NOT EXISTS VS LEFT JOIN...IS NULL性能分析(十八)

    前言 本节我们来综合比较NOT IN VS NOT EXISTS VS LEFT JOIN...IS NULL的性能,简短的内容,深入的理解,Always to review the basics. ...

  6. C#反序列化XML异常:在 XML文档(0, 0)中有一个错误“缺少根元素”

    Q: 在反序列化 Xml 字符串为 Xml 对象时,抛出如下异常. 即在 XML文档(0, 0)中有一个错误:缺少根元素. A: 首先看下代码: StringBuilder sb = new Stri ...

  7. 数塔问题(DP算法)自底向上计算最大值

    Input 输入数据首先包括一个整数C,表示测试实例的个数,每个测试实例的第一行是一个整数N(1 <= N <= 100),表示数塔的高度,接下来用N行数字表示数塔,其中第i行有个i个整数 ...

  8. “老坛泡新菜”:SOD MVVM框架,让WinForms焕发新春

    火热的MVVM框架 最近几年最热门的技术之一就是前端技术了,各种前端框架,前端标准和前端设计风格层出不穷,而在众多前端框架中具有MVC,MVVM功能的框架成为耀眼新星,比如GitHub关注度很高的Vu ...

  9. HTML学习笔记

    HTML学习笔记 2016年12月15日整理 Chapter1 URL(scheme://host.domain:port/path/filename) scheme: 定义因特网服务的类型,常见的为 ...

  10. ADFS3.0与SharePoint2013安装配置(原创)

    现在越来越多的企业使用ADFS作为单点登录,我希望今天的内容能帮助大家了解如何配置ADFS和SharePoint 2013.安装配置SharePoint2013这块就不做具体描述了,今天主要讲一下怎么 ...