zoukankan      html  css  js  c++  java
  • LINQ之路15:LINQ Operators之元素运算符、集合方法、量词方法

    本篇继续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 = { 1, 2, 3, 4, 5 };
    int first = numbers.First(); // 1
    int last = numbers.Last(); // 5
    int firstEven = numbers.First(n => n % 2 == 0); // 2
    int lastEven = numbers.Last(n => n % 2 == 0); // 4

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

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

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

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

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

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

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

    ElementAt

    参数

    类型

    源sequence

    IEnumerable<TSource>

    待返回元素的索引

    int

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

                int[] numbers = { 1, 2, 3, 4, 5 };
    int third = numbers.ElementAt(2); // 3
    int tenthError = numbers.ElementAt(9); // Exception
    int tenth = numbers.ElementAtOrDefault(9); // 0

    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[] { 5, 6, 7 }.Count();  // 3

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

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

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

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

    Min 和Max

    参数

    类型

    源sequence

    IEnumerable<TSource>

    结果选择器(可选)

    TSource => TResult

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

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

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

                int smallest = numbers.Max(n => n % 10);  // 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 = { 3, 4, 8 };
    decimal sumTotal = numbers.Sum(); // 15
    decimal average = numbers.Average(); // 5

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

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

    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[] { 3, 4 }.Average();
    // But this will compile:
    double avg2 = new int[] { 3, 4 }.Average(); // 3.5

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

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

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

    Aggregate

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

                int[] numbers = { 2, 3, 4 };
    int sum = numbers.Aggregate(0, (total, n) => total + n); // 9

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

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

    不带种子的集合计算

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

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

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

                int[] numbers = { 1, 2, 3 };
    int x = numbers.Aggregate(0, (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[] { 2, 3, 4 }.Contains(3); // true;

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

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

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

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

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

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

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

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

    All 和SequenceEqual

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

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

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

                int[] numbers1 = { 2, 3, 4 };
    int[] numbers2 = { 2, 3, 4 };
    int[] numbers3 = { 3, 2, 4 };

    Console.WriteLine(numbers1.SequenceEqual(numbers2)); // True
    Console.WriteLine(numbers1.SequenceEqual(numbers3)); // False
  • 相关阅读:
    超参数(Hyperparameter)
    验证和交叉验证(Validation & Cross Validation)
    训练集,验证集,测试集(以及为什么要使用验证集?)(Training Set, Validation Set, Test Set)
    特征的非线性变换(Feature Non-linear Transformation)
    机器学习---三种线性算法的比较(线性回归,感知机,逻辑回归)(Machine Learning Linear Regression Perceptron Logistic Regression Comparison)
    Numpy练习题
    过拟合产生的原因(Root of Overfitting)
    超哥笔记 ---集群、负载均衡、代理(7)
    搭建前端项目(2)
    超哥笔记 --nginx入门(6)
  • 原文地址:https://www.cnblogs.com/qixuejia/p/7284826.html
Copyright © 2011-2022 走看看