本篇继续LINQ Operators的介绍,包括元素运算符/Element Operators、集合方法/Aggregation、量词/Quantifiers Methods。元素运算符从一个sequence当中获取单个元素;集合方法对sequence进行统计/汇总并返回当个标量值;量词方法用于判断sequence是否满足特定条件并返回bool值。

元素运算符/Element Operators

IEnumerable<TSource>→TSource

Operator

说明

SQL语义

First,

FirstOrDefault

返回sequence中(可选满足某个条件)的第一个元素

SELECT TOP 1 ... ORDER BY ...

Last,

LastOrDefault

返回sequence中(可选满足某个条件)的最后一个元素

SELECT   TOP 1 ... ORDER BY ... DESC

Single, SingleOrDefault

相当于First/FirstOrDefault,但是如果不止一个匹配元素则抛出异常

ElementAt, ElementAtOrDefault

返回特定位置上的元素

Exception   thrown

DefaultIfEmpty

如何sequence没有元素则返回null或default(TSource)

OUTER JOIN

以 “OrDefault”结束的方法在输入sequence为空或没有匹配的元素时返回default(TSource),而不是抛出异常。default(TSource)对于引用类型的元素来说等于null,对于值类型元素则通常等于0。

First, Last, and Single

参数

类型

源sequence

IEnumerable<TSource>

条件(可选)

TSource => bool

下面的例子示范了First和Last的方法:

            int[] numbers = { , , , ,  };
int first = numbers.First(); //
int last = numbers.Last(); //
int firstEven = numbers.First(n => n % == ); //
int lastEven = numbers.Last(n => n % == ); //

下面的例子对First和FirstOrDefault进行了对比:

            int firstBigError = numbers.First(n => n > ); // Exception
int firstBigNumber = numbers.FirstOrDefault(n => n > ); //

对于Single运算符来说,必须只能有且仅有一个匹配元素,否则将会抛出异常;SingleOrDefault可以有一个或零个匹配元素:

            int onlyDivBy3 = numbers.Single(n => n %  == );           //
int divBy2Err = numbers.Single(n => n % == ); // Error: 2 & 4 match
int singleError = numbers.Single(n => n > ); // Error
int noMatches = numbers.SingleOrDefault(n => n > ); //
int divBy2Error = numbers.SingleOrDefault(n => n % == ); // Error

Single是上面这个家族中最“严格”的元素运算符,而FirstOrDefault和LastOrDefault则是最宽松的。

在LINQ to SQL和EF,Single经常用来在一个表中根据主键获取一行数据:

            Customer cust = dataContext.Customers.Single(c => c.ID == );

ElementAt

参数

类型

源sequence

IEnumerable<TSource>

待返回元素的索引

int

ElementAt获取sequence中特定位置上的元素:

            int[] numbers = { , , , ,  };
int third = numbers.ElementAt(); //
int tenthError = numbers.ElementAt(); // Exception
int tenth = numbers.ElementAtOrDefault(); //

DefaultIfEmpty

DefaultIfEmpty把一个空sequence转换为null/default()。它用来书写平展的outer join,请参考:LINQ之路12:LINQ Operators之数据转换(Projecting)中的SelectMany中的Outer joins一节。

集合方法/Aggregation Methods

IEnumerable<TSource>→ scalar

Operator

说明

SQL语义

Count, LongCount

返回输入sequence中的元素个数,可以指定某个条件

COUNT (...)

Min, Max

返回输入sequence中的最小/最大元素

MIN   (...), MAX (...)

Sum, Average

对sequence中的元素求和或平均值

SUM (...), AVG (...)

Aggregate

执行定制的计算

抛出异常

Count 和LongCount

参数

类型

源sequence

IEnumerable<TSource>

条件(可选)

TSource => bool

Count简单地遍历某个sequence,返回其元素个数:

            int fullCount = new int[] { , ,  }.Count();  //

Enumerable.Count的内部实现会判断输入sequence是否实现了ICollection<T>接口,如果是,则调用ICollection<T>.Count,否则遍历sequence中的每个元素并进行计数。

我们可以选择提供一个条件:

            int digitCount = "pa55w0rd".Count(c => char.IsDigit(c));    //

LongCount的功能与Count一样,但是返回64-bit整数,这样就允许遍历元素超过32-bit整数范围的sequence。

Min 和Max

参数

类型

源sequence

IEnumerable<TSource>

结果选择器(可选)

TSource => TResult

Min和Max返回输入sequence中的最小/最大元素:

            int[] numbers = { , ,  };
int smallest = numbers.Min(); // 14;
int largest = numbers.Max(); // 32;

如果我们提供了选择器表达式,每个元素都会先进行数据转换:

            int smallest = numbers.Max(n => n % );  // 8;

如果元素本质上不支持比较,那么选择器表达式就是必须的。换句话说,如果他们没有实现IComparable<T>:

            Purchase runtimeError = dataContext.Purchases.Min(); // Error
decimal? lowestPrice = dataContext.Purchases.Min(p => p.Price); // OK

选择器表达式不只是决定了元素的比较方式,而且决定了最终的结果。上面使用p => p.Price的示例中,最终结果是一个decimal数值,而不是purchase对象。如果要想得到最便宜的purchase,我们需要一个子查询:

            Purchase cheapest = dataContext.Purchases
.Where(p => p.Price == dataContext.Purchases.Min(p2 => p2.Price))
.FirstOrDefault();

当然上面这个例子中,我们也可以不使用Min,而用OrderBy来获得相同的结果。

Sum和Average

参数

类型

源sequence

IEnumerable<TSource>

结果选择器(可选)

TSource => TResult

Sum和 Average的使用方式和Min/Max类似,他们用于对sequence中的元素求和或平均值:

            decimal[] numbers = { , ,  };
decimal sumTotal = numbers.Sum(); //
decimal average = numbers.Average(); //

下面的查询返回names数组中每个字符串的总长度:

            string[] names = { "Tom", "Dick", "Harry", "Mary", "Jay" };
int combinedLength = names.Sum(s => s.Length); //

Sum和Average对他们操作的元素类型相当严格,他们可以操作下面这些数值类型(int, long, float, double, decimal, 和他们的可空版本)。而Min和Max可以直接操作任何实现了IComparable<T>的对象,如string。并且, Average总是参照下表返回decimal或者double类型的结果:

选择器类型

结果类型

decimal

decimal

int, long, float, double

double

这意味着下面的查询无法编译 (“cannot convert double to int”):

            // cannot convert double to int
int avg = new int[] { , }.Average();
// But this will compile:
double avg2 = new int[] { , }.Average(); // 3.5

为了防止丢失数据精度,Average隐式地把输入数值转换到更宽的数据类型。

当查询数据库时,Sum和Average会被翻译到标准的SQL 集合运算符。下面的查询返回purchase平均值超过500的Customers:

            var query = from c in dataContext.Customers
where c.Purchases.Average (p => p.Price) >
select c.Name;

Aggregate

Aggregate允许我们使用定制的算法来完成不常见的汇总/计算。Aggregate在LINQ to SQL和Entity Framework中不被支持,并且它的使用方法有些特殊。下面的示例用Aggregate完成了Sum的功能:

            int[] numbers = { , ,  };
int sum = numbers.Aggregate(, (total, n) => total + n); //

Aggregate的第一个参数是算法的种子,即初始值。第二个参数是一个表达式,用来针对每个元素更新计算数值。我们可以选择提供第三个参数来对最终结果进行数据转换。

Aggregate可以解决的很多问题同样可以使用foreach循环(更熟悉的语法形式)来完成。使用Aggregate的优势是对于复杂的计算,我们可以使用PLINQ自动实现平行的计算任务。

不带种子的集合计算

当调用Aggregate时,我们可以省略种子值,这时第一个元素会隐式成为种子值,并且集合计算从第二个元素继续下去。

            // 省去种子参数调用Aggregate
int[] numbers = { , , };
int sum = numbers.Aggregate ((total, n) => total + n); //

这个例子完成和上面例子同样的功能(求和),但是实际上我们完成了两个不同的计算。前一个例子,我们计算0+1+2+3;现在我们计算的是1+2+3。我们可以使用乘法来更好的展示他们之间的区别:

            int[] numbers = { , ,  };
int x = numbers.Aggregate(, (prod, n) => prod * n); // 0*1*2*3 = 0
int y = numbers.Aggregate((prod, n) => prod * n); // 1*2*3 = 6

量词/Quantifiers

IEnumerable<TSource>→bool

Operator

说明

SQL语义

Contains

如果输入sequence包含给定的element则返回true

WHERE ... IN (...)

Any

如果任意一个元素满足给定条件则返回true

WHERE   ... IN (...)

All

如果所有元素都满足给定条件则返回true

WHERE (...)

SequenceEqual

如果第二个sequence和输入sequence拥有相同的elements则返回true

Contains 和Any

Contains方法接受一个TSource类型参数;Any可选地接受一个条件表达式。

如果输入sequence包含给定的element,Contains返回true:

            bool hasAThree = new int[] { , ,  }.Contains(); // true;

如果任意一个元素满足给定条件,Any返回true。我们可以使用Any来重写上面的查询:

            bool hasAThree = new int[] { , ,  }.Any(n => n == ); // true;

Any可以完成Contains可以完成的任何事情,也能完成Contains不能完成的事情:

            bool hasABigNumber = new int[] { , ,  }.Any(n => n > ); // false;

如果调用Any时省略了条件表达式,则只要sequence中含有元素就返回true,下面使用另一种方式完成了上面查询的功能:

            bool hasABigNumber = new int[] { , ,  }.Where(n => n > ).Any();

Any在我们使用子查询时非常有用,并且经常用在数据库查询中,比如:

            var query =
from c in dataContext.Customers
where c.Purchases.Any(p => p.Price > )
select c;

All 和SequenceEqual

如果所有的元素都符合给定条件,则All返回true。下面的查询返回所有purchases都小于100的customers:

            var query =
dataContext.Customers.Where(c => c.Purchases.All(p => p.Price < ));

SequenceEqual比较两个sequence。如果他们拥有相同的元素,且相同的顺序,则返回true:

            int[] numbers1 = { , ,  };
int[] numbers2 = { , , };
int[] numbers3 = { , , }; Console.WriteLine(numbers1.SequenceEqual(numbers2)); // True
Console.WriteLine(numbers1.SequenceEqual(numbers3)); // False

LINQ之路15:LINQ Operators之元素运算符、集合方法、量词方法的更多相关文章

  1. LINQ之路16:LINQ Operators之集合运算符、Zip操作符、转换方法、生成器方法

    本篇将是关于LINQ Operators的最后一篇,包括:集合运算符(Set Operators).Zip操作符.转换方法(Conversion Methods).生成器方法(Generation M ...

  2. LINQ之路11:LINQ Operators之过滤(Filtering)

    在本系列博客前面的篇章中,已经对LINQ的作用.C# 3.0为LINQ提供的新特性,还有几种典型的LINQ技术:LINQ to Objects.LINQ to SQL.Entity Framework ...

  3. LINQ之路(3):LINQ扩展

    本篇文章将从三个方面来进行LINQ扩展的阐述:扩展查询操作符.自定义查询操作符和简单模拟LINQ to SQL. 1.扩展查询操作符 在实际的使用过程中,Enumerable或Queryable中的扩 ...

  4. LINQ之路 7:子查询、创建策略和数据转换

    在前面的系列中,我们已经讨论了LINQ简单查询的大部分特性,了解了LINQ的支持计术和语法形式.至此,我们应该可以创建出大部分相对简单的LINQ查询.在本篇中,除了对前面的知识做个简单的总结,还会介绍 ...

  5. LINQ之路 4:LINQ方法语法

    书写LINQ查询时又两种语法可供选择:方法语法(Fluent Syntax)和查询语法(Query Expression). LINQ方法语法是非常灵活和重要的,我们在这里将描述使用链接查询运算符的方 ...

  6. LINQ之路(2):LINQ to SQL本质

    LINQ之路(2):LINQ to SQL本质 在前面一篇文章中回顾了LINQ基本语法规则,在本文将介绍LINQ to SQL的本质.LINQ to SQL是microsoft针对SQL Server ...

  7. .NET面试题系列[15] - LINQ:性能

    .NET面试题系列目录 当你使用LINQ to SQL时,请使用工具(比如LINQPad)查看系统生成的SQL语句,这会帮你发现问题可能发生在何处. 提升性能的小技巧 避免遍历整个序列 当我们仅需要一 ...

  8. [转]LINQ之路系列博客导航

    分享一个学习Linq的好博客:Linq之路

  9. LINQ之路 1: LINQ介绍

    LINQ是.NET Framework 3.5的新特性,其全称是 Language Integrated Query,即语言集成查询,是指将查询功能和语言结合起来.从而为我们提供一种统一的方式,让我们 ...

随机推荐

  1. tuple的基本使用

    常用如下所示: # 元祖,tuple-->不可变,但元祖里面的数据可以变化 # 当元祖只有一个元素时,需加’,‘,否则类型是<class 'int'> # tuple1 = (1) ...

  2. java+js实现展示本地文件夹下的所有图片demo[申明:来源于网络]

    java+js实现展示本地文件夹下的所有图片demo[申明:来源于网络] 地址:http://blog.csdn.net/allgis/article/details/46364875

  3. phpspider php爬虫框架

    其实我自身的不是经常写正则,而且不规则的html去写正则本身就是件很麻烦的事情,如果页面有些微变动和更新就得再次去维护正则表达式,其实是非常蛋疼的 我第一感觉就是去找一下爬虫的库,但是发现现在php爬 ...

  4. css学习_css定位

    1.定在某个位置:简称定位 2.浮动和定位的区别 定位的分类:定位模式 a.静态定位:(标准流) b.相对定位(不脱离文档流)---以自己左上角为基准点定位 c.绝对定位absolute  (拼爹型: ...

  5. Nginx+Tomcat整合的安装与配置(win.linux)

    //原帖 http://zyjustin9.iteye.com/blog/2017394 上面是windows系统,linux直接下拉到分割线. 相信很多人都听过nginx,这个小巧的东西慢慢地在吞食 ...

  6. jQuery 实现点击页面其他地方隐藏菜单

    点击页面其它地方隐藏id为messageList的div 代码: $('body').delegate("#message", 'click', function(e) { var ...

  7. Spark application注册master机制

    直接上Master类的代码: case RegisterApplication(description) => { if (state == RecoveryState.STANDBY) { / ...

  8. 洛谷P3516 PRZ-Shift [POI2011] 构造

    正解:构造 解题报告: 传送门! umm这题就是很思维的?就是想到了就A了想不到就做不出来,然而我也只能是做到理解不知道怎么想出来,,,感觉构造题什么的就很真诚,一点套路也没有,所以像我这种没有脑子只 ...

  9. mongodb删除重复数据

    注:mongodb当前版本是3.4.3   插入六条数据:   查询存在重复的数据:   查询并循环删除重复数据:   删除语句解析: db.userInfo.aggregate([     {   ...

  10. 安装和使用ZFS

    一.安装和使用ZFS Centos7上安装和使用ZFS:https://blog.csdn.net/linuxnews/article/details/51286358