重庆熊猫 Loading

.NET教程 - LINQ

更新记录
转载请注明出处:
2022年9月30日 发布。
2022年9月29日 从笔记迁移到博客。

LINQ基础(LINQ Fundamentals)

LINQ介绍说明

LINQ(发音Link)语言集成查询(Language Intergrated Query)

LINQ是.NET框架的扩展,允许我们以使用SQL类似的语法查询数据集合,可以嵌入到.NET支持的语言中,比如:C#和VB。但要注意LINQ和SQL很类似,但是两者是完全不同的东西。查询的数据源可以是Array、List、XML、JSON、数据库等。通过使用IEnumerable<T>IQueryable<T>实现对数据源的查询和操作。LINQ还支持可以从远程数据源(如sqlserver数据库)动态提供的序列。standard query operators are implemented as extension methods

注意:

  • A query operator never alters the input sequence; instead, it returns a new sequence。
  • Each method on IEnumerable<T> is a standard query operator,it provides querying capability over the collection on which it operates。
  • LINQ定义在using System.Linq;命名空间下。
  • LINQ中的Enumerable接口的扩展方法定义在System.Linq命名空间中。
  • 该命名空间中定义了超过了40个查询运算符。
  • 所有的定义都是静态扩展方法(static extension methods)。
  • 使用LINQ项目必须基于.NET Framework 3.5以上。

LINQ的作用(为什么要使用LINQ)

  • 更加高效、快速、简单的查询、操作数据。
  • 提高代码的可读性、可维护性。
  • 在程序中可以直接使用类似SQL的数据查询语法,类似SQL上手简单。
  • 提高开发效率

LINQ的优势

1、熟悉的语言:开发人员不必为每种类型的数据源或数据格式学习新的语言。
2、更少的编码:相比较传统的方式,LINQ减少了要编写的代码量。
3、可读性强:LINQ增加代码可读性,因此其他开发人员可以很轻松地理解和维护。
4、标准化的查询方式:可以使用相同的LINQ语法查询多个数据源。
5、类型检查:程序会在编译的时候提供类型检查。
6、智能感知提示:LINQ为通用集合提供智能感知提示。
7、整形数据:LINQ可以检索不同形状的数据。

LINQ组成

LINQ由不同的部分组成,分别是 必须的部分 和 可选的部分

扩展方法(Extension methods)

这是必须的部分

比如Where、OrderBy、Select

LINQ数据提供工具(LINQ providers)

​ 这是必须的部分

​ 用于处理不同的数据源

​ 比如LINQ to Objects, LINQ to Entities, LINQ to XML, LINQ to OData、LINQ to Amazon

Lambda表达式(Lambda expressions)

​ 这是可选的部分

​ 用于代替类似SQL语法的查询语法

LINQ查询语法(LINQ query comprehension syntax)

​ 这是可选的部分

​ 类似SQL的查询语法

比如from, in, where, orderby, descending, and select

主要命名空间

using  System.Linq              // LINQ to Objects and PLINQ
using  System.Linq.Expressions // For building expressions manually
using  System.Xml.Linq         // LINQ to XML

LINQ数据提供程序

LINQ支持不同的数据源

比如:SQL数据库、对象、XML等,需要由不同的提供程序进行支持

image

LINQ to XML 使用LINQ操作和查询XML文档

LINQ to SQL 针对SQL的查询

LINQ to Dataset 针对ADO.NET DataSet对象使用的LINQ

LINQ to Entity 针对ADO.NET Entity Framework(EF)的LINQ

LINQ to Objects 针对数组和集合的LINQ查询

Parallel LINQ 并行处理LINQ查询返回的数据

LINQ还可以自己进行扩展,比如:LINQ to Amazon

LINQ to SQL组件,可以查询基于关系数据库的数据,并对这些数据进行检索、插入、修改、删除、排序、聚合、分区等操作

LINQ to DataSet组件,可以查询DataSet对象中的数据,并对这些数据进行检索、过滤、排序等操作

LINQ to Objects组件,可以查询Ienumerable或Ienumerable集合,也就是可以查询任何可枚举的集合,如数据(Array和ArrayList)、泛型列表List、泛型字典Dictionary等,以及用户自定义的集合,而不需要使用LINQ提供程序或API

LINQ to XML组件,可以查询或操作XML结构的数据(如XML文档、XML片 段、XML格式的字符串等),并提供了修改文档对象模型的内存文档和支持LINQ 查询表达式等功能,以及处理XML文档的全新的编程接口

LINQ相关的泛型接口

image

LINQ注意问题

LINQ是强类型

如果需要立即获得值,使用转换API

最好定义在方法内

LINQ不是强制使用的,在一定条件下可以不使用

LINQ规范

使用隐式var进行声明

因为一般返回类型是一个IEnumerable接口的实例类型

匿名对象

即不需要类即可直接生成一个对象,类似Javascript中对象直接量

语法

image

使用

image

注意

匿名类型只能用在局部变量中,不能作为类成员

由于匿名类型没有名字,所以只能使用var作为变量的类型

不能设置匿名类型对象的属性,编译去为匿名类型创建的属性是只读的

LINQ语句延迟执行(Deferred Execution)(Lazy Evaluation)

LINQ语句会延迟执行

而不是在创建的时候就执行,而是在访问的时候才执行

以下情况不会延迟执行:

1、运算返回单个值或标量值(single element or scalar)

​ 比如:element、aggregation、quantifiers operators

2、存在转换操作符

​ 比如:ToArray、ToList、ToDictionary、ToLookup、ToHashSet

LINQ操作的三种分类

Sequence in, sequence out (sequence→sequence)

Sequence in, single element or scalar value out

Nothing in, sequence out (generation methods)

Sequence→Sequence

说明

大部分的LINQ操作都是属于这种类型

示意图

image

主要包含LINQ操作

FILTERING(过滤)

IEnumerable→IEnumerable

Returns a subset of the original elements

With each of the filtering methods, you always end up with either the same number or fewer elements than you started with

主要操作方法:

Where Returns a subset of elements that satisfy a given condition

Take Returns the first count elements and discards the rest

Skip Ignores the first count elements and returns the rest

TakeWhile Emits elements from the input sequence until the predicate is false

SkipWhile Ignores elements from the input sequence until the predicate is false

and then emits the rest

Distinct Returns a sequence that excludes duplicates

PROJECTING(投影)

IEnumerable→IEnumerable

Transforms each element with a lambda function

主要操作方法:

Select, SelectMany

JOINING(连接)

IEnumerable, IEnumerable→IEnumerable

Meshes elements of one sequence with another

主要操作方法:

Join, GroupJoin, Zip

ORDERING(排序)

IEnumerable→IOrderedEnumerable

Returns a reordering of a sequence

主要操作方法:

OrderBy, OrderByDescending, ThenBy, ThenByDescending, Reverse

GROUPING(分组)

IEnumerable→IEnumerable<IGrouping<TKey,TElement>>

Groups a sequence into subsequences

主要操作方法:

GroupBy

SET OPERATORS(集合操作符)

IEnumerable, IEnumerable→IEnumerable

Takes two same-typed sequences and returns their commonality, sum, or difference

主要操作方法:

Concat, Union, Intersect, Except

CONVERSION METHODS: IMPORT(转换方法:导入)

IEnumerable→IEnumerable

主要操作方法:

OfType, Cast

CONVERSION METHODS: EXPORT(转换方法:导出)

IEnumerable→An array, list, dictionary, lookup, or sequence

主要操作方法:

ToArray, ToList, ToDictionary, ToLookup, AsEnumerable, AsQueryable

Sequence→Element or Value

说明

主要包含LINQ操作

ELEMENT OPERATORS(元素操作)

IEnumerable→TSource

Picks a single element from a sequence

主要操作方法:

First, FirstOrDefault, Last, LastOrDefault, Single, SingleOrDefault,

ElementAt, ElementAtOrDefault, DefaultIfEmpty

AGGREGATION METHODS(聚合操作)

IEnumerable→scalar

Performs a computation across a sequence, returning a scalar value (typically a number)

主要操作方法:

Aggregate, Average, Count, LongCount, Sum, Max, Min

QUANTIFIERS(逻辑比较)

IEnumerable→bool

An aggregation returning true or false

主要操作方法:

All, Any, Contains, SequenceEqual

Void→Sequence

说明

主要包含LINQ操作

GENERATION METHODS(生成方法)

void→IEnumerable

Manufactures a simple sequence

主要操作方法:

Empty, Range, Repeat

方法语法(extension methods) 和 查询语法(Query Expressions)

概述

LINQ支持两种形式的语法:

查询表达式语法(Query Expressions) 和 方法语法(extension methods)

查询表达式语法(Query Expressions):和SQL类似,使用查询表达式形式书写

方法语法(extension methods):使用标准的方法调用,使用Fluent Syntax风格

注意:接受值并返回bool的lambda表达式称为谓词(predicate)

查询表达式(Query expressions) 和 方法调用(fluent queries)对比

查询表达式支持的操作少于方法调用,有时候需要转为方法调用形式或混合方法调用

查询表达式可以使用let子句

方法链式(extension methods)调用示意图

image

查询表达式(Query Expressions)结构示意图

image

混合式查询(Mixed-Syntax Queries)

可以混合 LINQ方法形式 和 LINQ表达式形式 的语法进行查询

实例:混合筛选

int[] tests = new int[] { 1, 2, 3, 4, 5 };
int result = (from item in tests where item > 3 select item).Count();
Console.WriteLine(result); //2

查询表达式语法(Query Expressions)

说明

查询语法是声明式的,方法语法是命令式的

查询语法 和 方法语法 没有性能差异,编译器会将查询语法转为方法调用形式

查询表达式总是以from子句开头,以select或group子句结尾

编译器最终会将查询表达式转为方法调用的形式来处理LINQ

image

实例:

using System;
using System.Collections.Generic;
using System.Linq;

namespace Panda
{
    class Panda
    {
        static void Main(string[] args)
        {
            int[] numbers = { 1, 2, 3, 4, 5, 6, 7 }; //对象集合

            //查询语法
            IEnumerable<int> minNumber1 = from i in numbers
                                        where i <= 3
                                        select i;
            foreach (int item in minNumber1)
            {
                Console.WriteLine(item);
            }

            //查询语法
            IEnumerable<int> minNumber2 = numbers.Where(x => x <= 3);
            foreach (int item in minNumber2)
            {
                Console.WriteLine(item);
            }
            Console.ReadKey();
        }
    }
}

还可以把查询语法和方法语法结合使用

using System;
using System.Linq;
using System.Collections.Generic;

namespace ConsoleApp3
{

    class Program
    {
        
        static void Main(string[] args)
        {
            int[] numbers = new int[]
            {
                1,2,3,4,5,6,7
            };

            //结合使用
            int queryResult = (from n in numbers
                               where n < 3
                               select n).Count();

            Console.WriteLine(queryResult);

            //wait
            Console.ReadKey();
        }
    }
}

查询表达式语法结构(Query expression syntax)图

image

LINQ查询语法与SQL语法对比(Query Syntax Versus SQL Syntax)

LINQ查询语法遵循C#表达式

LINQ操作按元素顺序处理,是有序的

LINQ方法形式 与 查询表达式形式对比(Query Syntax Versus Fluent Syntax)

查询表达式在以下方面更加方便:

使用let子句进行引入新的临时变量

使用SelectMany, Join, or GroupJoin子句

单个子句的情况下,方法形式更加方便

查询变量

LINQ查询的返回值为可枚举类型(不是枚举类型) 或 标量(scalar)

image

说明:

​ 如果查询表达式返回可枚举类型,查询会一直等到出来可枚举变量时才执行

​ 如果可枚举变量被处理多次,查询就会执行多次

​ 如果可枚举变量在遍历之后,查询之前的数据有改动,查询会使用新数据

​ 如果查询表达式返回标量,查询立即执行,并且把结果保存在查询变量中

避免LINQ多次执行

To avoid such repeated execution, you must cache the data that the executed query retrieves

To do so, you assign the data to a local collection using one of the To collection methods

During the assignment call of a To method, the query obviously executes

However, iterating over the assigned collection after that point will not involve the query expression any further

In general, if you want the behavior of an in-memory collection snapshot,

it is a best practice to assign a query expression to a cached collection to avoid unnecessary iterations

范围变量(Range Variables)

The identifier immediately following the from keyword syntax is called the range variable

实例:

from    n in names           // n is our range variable
where   n.Contains ("a")     // n = directly from the array
orderby n.Length             // n = subsequent to being filtered
select  n.ToUpper()          // n = subsequent to being sorted

可以通过以下方式引入range variables:

let
into
An additional from clause
join

let关键字

在查询表达式中可以使用let关键字引入一个临时的变量

实例:

string[] names = { "Tom","Dick","Harry","Mary","Jay" };

IEnumerable<string> query =
                from n in names
                let vowelless = Regex.Replace (n, "[aeiou]", "")
                where vowelless.Length > 2
                orderby vowelless
                select n + " - " + vowelless;

查询延续(Query Continuations)

使用into关键字延续查询

注意:into子句必须要放在select和group后面

实例:

from c in "The quick brown tiger".Split()
select c.ToUpper() into upper
where upper.StartsWith ("T")
select upper

延迟执行(Deferred Execution)

说明

LINQ语句一般都会在使用的时候才会执行,除以下情况:

Operators that return a single element or scalar value, such as First or Count

包含转换操作ToArray, ToList, ToDictionary, ToLookup, ToHashSet

重新评估(Reevaluation)

在执行时会再次检测序列,以最新的序列进行执行LINQ操作

重新评估的缺点

有时候想锁住或缓存序列的当前值

密集查询/远程查询没有缓存,重复计算会导致效率低下

实例:重新评估

var numbers = new List<int>() { 1, 2 };
IEnumerable<int> query = numbers.Select (n => n * 10);
foreach (int n in query) Console.Write (n + "|");   // 10|20|
numbers.Clear();
foreach (int n in query) Console.Write (n + "|");   // <nothing>

防止重复评估的方法

将序列的LINQ查询结果转为其他集合,比如使用ToArray or ToList操作

实例:防止重复评估执行

var numbers = new List<int>() { 1, 2 };
List<int> timesTen = numbers
                    .Select (n => n * 10)
                    .ToList(); // Executes immediately into a List<int>
numbers.Clear();
Console.WriteLine (timesTen.Count);      // Still 2

捕获变量(Captured Variables)

如果LINQ查询中的lambda表达式捕获外部变量

则在运行LINQ查询时再去获得变量的值

实例:运行LINQ时捕获变量值

int[] numbers = { 1, 2 };
int factor = 10;
IEnumerable<int> query = numbers.Select (n => n * factor);
factor = 20;
foreach (int n in query) Console.Write (n + "|");   // 20|40|

实例:运行LINQ时捕获变量值

IEnumerable<char> query = "Not what you might expect";
string vowels = "aeiou";
for (int i = 0; i < vowels.Length; i++)
{
    query = query.Where (c => c != vowels[i]);
}
//这里会报错
//因为循环已经退出,所以i超出了索引范围、
//抛出IndexOutOfRangeException 异常
foreach (char c in query) Console.Write (c);
//修复方式
// for (int i = 0; i < vowels.Length; i++)
// {
//   char vowel = vowels[i];
//   query = query.Where (c => c != vowel);
// }

延迟执行的内部原理(How Deferred Execution Works)

本质是装饰器(decorator)和代理(Proxy)设计模式

使用用户定义的条件来修饰序列

示意图

image

如果是多个LINQ操作,则会进行多层的装饰(Chaining Decorators)

注意:如果调用转换操作,比如ToList则会马上进行执行所有操作

image

LINQ查询如何执行(How Queries Are Executed)

执行LINQ查询会层层进行操作的调用,然后再返回数据

image

自定义LINQ操作

说明

只需要定义IEnumerable类型的扩展方法就可以了

实例:

public static IEnumerable<TResult> MySelect<TSource,TResult>(this IEnumerable<TSource> source, Func<TSource,TResult> selector)
{
  foreach (TSource element in source)
    yield return selector (element);
}

LINQ子查询(Subqueries)

A subquery is a query contained within another query’s lambda expression

类似SQL中的子查询

每当计算封闭lambda表达式时,都会执行子查询

这意味着子查询是根据外部查询的需要执行的

子查询示意图:

image

实例:包含子查询的LINQ查询

string[] musos = { "Item1", "Item2", "Item3", "Item5" };
IEnumerable<string> query = musos.OrderBy(m => m.Split().Last());

实例:跨Lambda表达式的变量

string[] names = { "Tom", "Dick", "Harry", "Mary", "Jay" };
IEnumerable<string> outerQuery = names
  .Where (n => n.Length == names.OrderBy (n2 => n2.Length)
                                .Select  (n2 => n2.Length).First());
// Tom, Jay

实例:子查询

IEnumerable<string> outerQuery =
                    from   n in names
                    where  n.Length ==
                        (from n2 in names orderby n2.Length select n2.Length).First()
                    select n;

LINQ操作组合策略(Composition Strategies)

渐进式查询构造(Progressive query construction)
将多个操作放置到多条语句中
使用into关键词(Using the into keyword)
将查询的结果放置到一个变量中,再进行其他查询
包裹查询(Wrapping queries)
类型与子查询

实例:渐进式查询构造

var filtered   = names    .Where   (n => n.Contains ("a"));
var sorted     = filtered .OrderBy (n => n);
var query      = sorted   .Select  (n => n.ToUpper());

实例:into关键字

IEnumerable<string> query =
            from   n in names
            select n.Replace ("a", "").Replace ("e", "").Replace ("i", "")
                    .Replace ("o", "").Replace ("u", "")
            into noVowel
                where noVowel.Length > 2 orderby noVowel select noVowel;

实例:包裹查询

IEnumerable<string> query =
                    from n1 in
                    (
                    from   n2 in names
                    select n2.Replace ("a", "").Replace ("e", "").Replace ("i", "")
                            .Replace ("o", "").Replace ("u", "")
                    )
                    where n1.Length > 2 orderby n1 select n1;

投影策略(Projection Strategies)

说明

最终生成的序列的类型

投影是什么

把集合中的每一项转换为另外一种类型。

IEnumerable<int> ages = list.Select(e =>e.Age);
IEnumerable<string> names = list.Select(e=>e.Gender?"男":"女");
var dogs = list.Select(p=>new Dog{NickName=e.Name,Age=e.Age});

主要有三种方式自定义生成的类型:

实例化指定类型(Object Initializers)

匿名类型(Anonymous Types)

使用let关键字(The let Keyword)

实例化指定类型(Object Initializers)

实例:实例化指定类型

select new TempClassItem
{
    Property1  = item.Property,
    Property2 = item.Property2
};

匿名类型(Anonymous Types)

实例:匿名类型

var intermediate = from n in names
                        select new
                        {
                            Property1 = item.Property1,
                            Property2 = item.Property2
                        };

实例:实例let关键字

IEnumerable<string> query =
                    from n in names
                    let vowelless = n.item
                    where vowelless.Length > 2
                    orderby vowelless
                    select n;       // Thanks to let, n is still in scope

解释查询(Interpreted Queries)

说明

LINQ provides two parallel architectures

local queries for local object collections

interpreted queries for remote data sources

本地查询(local queries)使用IEnumerable类型进行查询操作

远程查询(remote queries)使用IQueryable类型进行查询操作

IQueryable is an extension of IEnumerable with additional methods for constructing expression trees

IQueryable 继承自 IEnumerable

DbSet 继承自 IQueryable

将本地查询的IEnumerable转为IQueryable可以使用AsQueryable方法

将本地查询的IQueryable转为IEnumerable可以使用AsEnumerable方法

EF Core中的查询大都是IQueryable类型

实例:EF Core查询

IQueryable<string> query = from c in dbContext.Customers;

解释查询的工作原理(How Interpreted Queries Works)

First, the compiler converts query syntax to fluent syntax

Next, the compiler resolves the query operator methods

EF Core加载导航属性的值(LOADING NAVIGATION PROPERTIES)

默认情况下EF Core不会自动加载导航属性

方法一:使用Include()方法

var cust = dbContext.Customers
  .Include (c => c.Purchases)
  .Where (c => c.ID == 2).First();

方法二:使用投影

var custInfo = dbContext.Customers
  .Where (c => c.ID == 2)
  .Select (c => new
    {
      Name = c.Name,
      Purchases = c.Purchases.Select (p => new { p.Description, p.Price })
    })
  .First();

方法三:显式加载(explicit loading)

dbContext.Entry (cust).Collection (b => b.Purchases).Load();

延迟加载(LAZY LOADING)

设置全局延迟加载

dbContext.Entry (cust).Collection (b => b.Purchases).Load();
//引入命名空间
using Microsoft.EntityFrameworkCore.Proxies;
//在DbContext中设置
protected override void OnConfiguring (DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder.UseLazyLoadingProxies();
    //...
}

查询表达式结构语法

说明

子句必须按照一定的顺序出现

from和select子句是必须的,其他子句可选

与SQL不同,LINQ的select子句在表达式最后

可以有任意多个from….let…..where子句

image

每个子句概要:

image

查询语法汇总

Method Description
First, FirstOrDefault 获得第一个元素或者其类型的默认值 比如int默认为0,引用类型默认为null
Last, LastOrDefault 获得最后一个元素或者其类型的默认值 比如int默认为0,引用类型默认为null
Where 条件筛选
Single, SingleOrDefault 获得满足条件的单个元素或其默认值
ElementAt, ElementAtOrDefault 获得一个指定索引上的值或返回默认值
Select, SelectMany 选择元素的一部分或组成其他类型
OrderBy, OrderByDescending ThenBy, ThenByDescending 排序
Reverse 反序
GroupBy, GroupJoin, Join 分组和连接
Skip, SkipWhile 跳过匹配的元素
Take, TakeWhile 或者匹配的元素
Aggregate,Average,Count,LongCount Max, Min, Sum 获得聚合值
Cast 转换类型到特殊类型
OfType 删除与指定类型不匹配的项
Except, Intersect, Union 集合操作
Zip 根据的位置执行匹配操作项目
Distinct 从序列中删除重复项
ToArray, ToList, ToDictionary, ToLookup 将序列转换为数组或集合

from子句

from子句指定要作为数据源使用的数据集合

LINQ中from还可以包含迭代变量,迭代变量逐个表示数据源的每一个元素

from DataType item in Items

注意:

​ Type是集合中元素的类型,是可选的,编译器可以自行推断类型

​ Item是迭代变量名

​ Items是要查询的结合名字,集合必须是可枚举的

​ 可以有多个from子句

实例:基础使用

image

实例:使用多个from,有多个数据源 或 生成器(Multiple Generators)

image

与foreach的差异:

​ Foreach语句需要指定每个项的顺序,而LINQ中的from并没有声明顺序

​ foreach语句会立即执行,而LINQ from子句只在访问该变量时执行

实例:from引用多个源

IEnumerable<string> query = from n in numbers
                    from l in letters
                    select n.ToString() + l;

实例:from引用元素

IEnumerable<string> query =
                from fullName in fullNames
                from name in fullName.Split()
                select name + " came from " + fullName;

join子句

将两个集合结合创建一个临时对象集合,每一个对象包含原始集合对象中的所有字段

注意:使用关键字equals来进行连结,不能使用==运算符

image

实例:

image

let子句

let用于产生临时变量

let identifier = Expression

注意:

​ 不用带变量的类型声明

​ 可以有多个let子句

实例:

image

where子句

where用于筛选数据

where BooleanExpression

注意:

这个子句是可选的

可以有多个where子句

实例:

image

orderby子句

orderby子句用于结果集合排序

可选的ascending和descending关键字用于设置排序方向

注意:

orderby子句默认是升序的

可以有多个orderby子句

image

实例:

image

select子句

select子句用于说明指定所选的对象的哪部分要被select,可以是以下部分:
数据项、数据项的某个字段、数据项中的几个字段组成的新字段
select Expression

实例:获得数据项的某个字段

var query = from s in students
            select s.Name;

实例:获得数据项中的几个字段组成的新字段(匿名类型)

var query = from s in students
            select new { s.Name, s.Age, s.Major};

group…by子句

group…by子句用于设置结果集合的分组

语法:

group Expression1 by Expression2

注意:

group…by子句是可选的

分组的依据成为键(Key),可以使用Key属性进行引用

group返回的不是原始数据的可枚举类型,而是分组完成后的可枚举类型

实例:最基本的排序

using System;
using System.Linq;
using System.Collections.Generic;

namespace ConsoleApp3
{

    class Program
    {
        
        static void Main(string[] args)
        {
            //测试数据
            var testData = new[]{
                new { Name = "Panda",Age = 6666, Type = "Animal"},
                new { Name = "Dog", Age = 8888, Type = "Animal"},
                new { Name = "Tom", Age = 101, Type = "Man"},
                new { Name = "Jame", Age = 666, Type = "Man"}
            };

            //分组查询
            var queryResult = from n in testData
                              group n by n.Type;

            //输出结果
            foreach (var item in queryResult)
            {
                Console.WriteLine($"Group {item.Key}");
                foreach (var detail in item)
                {
                    Console.WriteLine($"{detail.Name} - {detail.Age} - {detail.Type}");
                }
            }

            //wait
            Console.ReadKey();
        }
    }
}

实例:分组排序后再对组内元素排序

List<string> animals = new List<string>()
            {
                "Panda", "Monkey", "Donkey",
                "Dog", "Bear", "Ant", "Cow",
                "Cat", "Lion", "Camel", "Elephant",
                "Frog", "Fox", "Goat", "Lamb"
            };

//进行分组然后排序
var result = from animal in animals
                group animal by animal[0].ToString().ToUpper() into g1
                orderby g1.Key //对组排序
                let list2 = (from ele in g1
                            orderby ele.ToUpper()
                            select ele  //对组内元素进行排序
                            )
                select (g1.Key, list2);
//遍历进行输出
foreach (var g in result)
{
    //输出组名
    Console.WriteLine(g.Key);
    //输出组内内容
    foreach (var eleInGroup in g.list2)
    {
        Console.WriteLine(eleInGroup);
    }
}

DISTINCT

语法:

DISTINCT

实例:

using System;
using System.Linq;
using System.Collections.Generic;

namespace ConsoleApp3
{

    class Program
    {
        static void Main(string[] args)
        {
            //测试数据
            int[] testData = new int[]
            {
                1,1,2,2,3,4,5,6,7,8
            };

            //查询
            var queryResult = (from n in testData
                               where n < 3
                               select n).Distinct();

            //输出结果
            foreach (var item in queryResult)
            {
                Console.WriteLine(item);
            }

            //wait
            Console.ReadKey();
        }
    }
}

聚合函数

Count()

Min()

Max()

Average()

Sum()

方法语法(extension methods)

说明

实例:用三种方式筛选数据

using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            //集合
            string[] names = { "Tom", "Dick", "Harry" };
            //LINQ筛选(静态方法调用形式)
            IEnumerable<string> filteredNames1 =
              System.Linq.Enumerable.Where(
                names, n => n.Length >= 4);
            
            //LINQ筛选(扩展方法调用形式)
            IEnumerable<string> filteredNames2 =
                names.Where(name => name.Length >= 4);
                
            //LINQ筛选(运算符调用形式)
            IEnumerable<string> filteredNames3 =
                from name in names
                where name.Length >= 4
                select name;

            //输出结果
            //foreach (string n in filteredNames1)
            //foreach (string n in filteredNames2)
            foreach (string n in filteredNames3)
            {
                Console.Write(n + "|"); //Dick|Harry|
            }

            //wait
            Console.ReadKey();
        }
    }
}

链式查询运算(Chaining Query Operators)

链式查询的图示

IEnumerable<string> query = names
                        .Where   (n => n.Contains ("a"))
                        .OrderBy (n => n.Length)
                        .Select  (n => n.ToUpper());

image

实例

string[] names = { "Tom","Dick","Harry","Mary","Jay" };
IEnumerable<string> query = names
                        .Where   (n => n.Contains ("a"))
                        .OrderBy (n => n.Length)
                        .Select  (n => n.ToUpper());
foreach (string name in query)
  Console.Write (name + "|");
// RESULT: JAY|MARY|HARRY|

标准查询运算符(Standard Query Operators)

分类

分类 Category 描述 Description 是否延迟执行 Deferred execution
Filtering Returns a subset of elements that satisfy a given condition Yes
Projecting Transforms each element with a lambda function, optionally expanding subsequences Yes
Joining Meshes elements of one collection with another, using a time-efficient lookup strategy Yes
Ordering Returns a reordering of a sequence Yes
Grouping Groups a sequence into subsequences Yes
Set Accepts two same-typed sequences, and returns their commonality, sum, or difference Yes
Element Picks a single element from a sequence No
Aggregation Performs a computation over a sequence, returning a scalar value (typically a number) No
Quantification Performs a computation over a sequence, returning true or false No
Conversion: Import Converts a nongeneric sequence to a (queryable) generic sequence Yes
Conversion: Export Converts a sequence to an array, list, dictionary, or lookup, forcing immediate evaluation No
Generation Manufactures a simple sequence Yes

Filtering operators

Method Description
Where Returns a subset of elements that satisfy a given condition
Take Returns the first x elements, and discards the rest
Skip Ignores the first x elements, and returns the rest
TakeWhile Emits elements from the input sequence until the given predicate is true
SkipWhile Ignores elements from the input sequence until the given predicate is true and then emits the rest
Distinct Returns a collection that excludes duplicates

Projection operators

Method Description
Select Transforms each input element with a given lambda expression
SelectMany Transforms each input element and then flattens and concatenates the resultant subsequences

joining operators

Method Description
Join Applies a lookup strategy to match elements from two collections, emitting a flat result set
GroupJoin As above, but emits a hierarchical result set
Zip Enumerates two sequences in step, returning a sequence that applies a function over each element pair

Ordering operators

Method Description
OrderBy, ThenBy Returns the elements sorted in ascending order
OrderByDescending, ThenByDescending Returns the elements sorted in descending order
Reverse Returns the elements in reverse order

Grouping operators

Method Description
GroupBy Groups a sequence into subsequences

集合运算符(Set operators)

说明

集合运算符支持两个相同类型的集合进行运算

集合运算符主要包括:Concat 和 Union

Method Description
Concat Concatenates two sequences
Union Concatenates two sequences, removing duplicates
Intersect Returns elements present in both sequences
Except Returns elements present in the first sequence, but not the second

元素操作符(Element operators)

说明

Not all query operators return a sequence

The element operators extract one element from the input sequence

Method Description
First, FirstOrDefault Returns the first element in the sequence, or the first element satisfying a given predicate
Last, LastOrDe⁠fault Returns the last element in the sequence, or the last element satisfying a given predicate
Single, Sin⁠gleOrDefault Equivalent to First/FirstOrDefault, but throws an exception if there is more than one match
ElementAt, Ele⁠mentAtOrDe⁠fault Returns the element at the specified position
DefaultI⁠fEmpty Returns a single-value sequence whose value is null or default(TSource) if the sequence has no elements

聚合操作(Aggregation operators)

说明

聚合操作通常返回值类型(scalar)

Method Description
Count, LongCount Returns the total number of elements in the input sequence, or the number of elements satisfying a given predicate
Min, Max Returns the smallest or largest element in the sequence
Sum, Average Calculates a numeric sum or average over elements in the sequence
Aggregate Performs a custom aggregation

量词(Qualifiers)

说明

quantifiers操作返回bool值

Method Description
Contains Returns true if the input sequence contains the given element
Any Returns true if any elements satisfy the given predicate
All Returns true if all elements satisfy the given predicate
Sequen⁠ceEqual Returns true if the second sequence has identical elements to the input sequence

Conversion operators (import)

Method Description
OfType Converts IEnumerable to IEnumerable, discarding wrongly typed elements
Cast Converts IEnumerable to IEnumerable, throwing an exception if there are any wrongly typed elements

Conversion operators (export)

Method Description
ToArray Converts IEnumerable to T[]
ToList Converts IEnumerable to List
ToDictionary Converts IEnumerable to Dictionary<TKey,TValue>
ToHashSet Converts IEnumerable to HashSet
ToLookup Converts IEnumerable to ILookup<TKey,TElement>
AsEnumerable Downcasts to IEnumerable
AsQueryable Casts or converts to IQueryable

Generation operators

Method Description
Empty Creates an empty sequence
Repeat Creates a sequence of repeating elements
Range Creates a sequence of integers

方法语法概览(旧的待删除)

image

image

image

image

image

基础查询语句(fundamental query)

Select

说明

INDEXED PROJECTION(索引)

select表达式可选的支持一个Index值

用于表示元素当前的序列

实例:INDEXED PROJECTION

string[] names = { "Tom", "Dick", "Harry", "Mary", "Jay" };
IEnumerable<string> query = names
  .Select ((s,i) => i + "=" + s);     //  { "0=Tom", "1=Dick", ... }

实例:

IEnumerable<string> query = from f in FontFamily.Families
                            select f.Name;

实例:

var query =
  from f in FontFamily.Families
  select new { f.Name, LineSpacing = f.GetLineSpacing (FontStyle.Bold) };     

SUBQUERIES AND JOINS IN EF CORE(子查询和连接在EF Core中)

实例:

var query =
  from c in dbContext.Customers
  select new {
               c.Name,
               Purchases = (from p in dbContext.Purchases
                           where p.CustomerID == c.ID && p.Price > 1000
                           select new { p.Description, p.Price })
                           .ToList()
             };

实例:基础选择

string[] names = { "Tom", "Dick", "Harry" };
IEnumerable<string> upperNames =
                        names.Select (n => n.ToUpper());
foreach (string n in upperNames)
{
    Console.Write (n + "|");       // TOM|DICK|HARRY|
}

实例:选择多个内容

var query = names.Select (n => new { 
                          Name = n,
                          Length = n.Length
                        });

foreach (var row in query)
{
    Console.WriteLine (row);
}

实例:筛选后再选择

from c in dbContext.Customers
where c.Name.StartsWith ("T")
from p in c.Purchases
select new { c.Name, p.Description };

实例:多条from语句

from c in dbContext.Customers
from p in c.Purchases
from pi in p.PurchaseItems
select new { c.Name, p.Description, pi.Detail };

实例:筛选多个元素

from c in dbContext.Customers
from p in c.Purchases.DefaultIfEmpty()
select new {
             c.Name,
             Descript = p == null ? null : p.Description,
             Price = p == null ? (decimal?) null : p.Price
           };

SelectMany

语法

from identifier1 in enumerable-expression1
from identifier2 in enumerable-expression2

实例:

string[] fullNames = { "Anne Williams", "John Fred Smith", "Sue Green" };
IEnumerable<string> query = fullNames.SelectMany (name => name.Split());
foreach (string name in query)
{
  Console.Write (name + "|");  // Anne|Williams|John|Fred|Smith|Sue|Green|
}
//等价于
//IEnumerable<string> query =
//   from fullName in fullNames
//   from name in fullName.Split()
//   select name + " came from " + fullName;

Where

说明

实例:EF Core中的LINQ操作使用类似SQL的LIKE形式

where EF.Functions.Like (c.Description, "%" + c.Name + "%")

实例:EF Core中的LINQ操作使用IN

WHERE customer.Name IN ("Tom", "Jay")

实例:用三种方式筛选数据

using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            //集合
            string[] names = { "Tom", "Dick", "Harry" };
            //LINQ筛选(静态方法调用形式)
            IEnumerable<string> filteredNames1 =
              System.Linq.Enumerable.Where(
                names, n => n.Length >= 4);
            
            //LINQ筛选(扩展方法调用形式)
            IEnumerable<string> filteredNames2 =
                names.Where(name => name.Length >= 4);
                
            //LINQ筛选(运算符调用形式)
            IEnumerable<string> filteredNames3 =
                from name in names
                where name.Length >= 4
                select name;

            //输出结果
            //foreach (string n in filteredNames1)
            //foreach (string n in filteredNames2)
            foreach (string n in filteredNames3)
            {
                Console.Write(n + "|"); //Dick|Harry|
            }

            //wait
            Console.ReadKey();
        }
    }
}

Take

说明

EF Core translates Take and Skip to the ROW_NUMBER function in SQL Server 2005,

or a TOP n subquery in earlier versions of SQL Server

Take operator outputs the first x elements

实例:

int[] numbers  = { 10, 9, 8, 7, 6 };
IEnumerable<int> firstThree = numbers.Take (3);
// firstThree is { 10, 9, 8 }

实例:

IQueryable<Book> query = dbContext.Books
  .Where   (b => b.Title.Contains ("mercury"))
  .OrderBy (b => b.Title)
  .Take (20);

Skip

说明

Skip operator ignores the first x elements, and outputs the rest

注意:LINQ中的Skip 是从1开始计数

实例:

int[] numbers  = { 10, 9, 8, 7, 6 };
IEnumerable<int> lastTwo = numbers.Skip (3);

实例:

IQueryable<Book> query = dbContext.Books
  .Where   (b => b.Title.Contains ("mercury"))
  .OrderBy (b => b.Title)
  .Skip (20).Take (20);

EF Core注意

注意:EF Core translates Take and Skip to the ROW_NUMBER function in SQL Server 2005,

or a TOP n subquery in earlier versions of SQL Server

Reverse

First

注意:如果没有找到匹配的元素会抛出异常

如果要避免异常需要使用FirstOrDefault,没有找到就会返回默认值

实例:

int[] numbers = { 10, 9, 8, 7, 6 };
int firstNumber = numbers.First();    // 10
int firstOddNum = numbers.First(n => n % 2 == 1);  // 9

Last

注意:如果没有找到匹配的元素会抛出异常

如果要避免异常需要使用LastOrDefault,没有找到就会返回默认值

实例:

int[] numbers = { 10, 9, 8, 7, 6 };
int lastNumber = numbers.Last();  // 6

Single

注意:如果没有找到匹配的元素会抛出异常

如果要避免异常需要使用SingleOrDefault,没有找到就会返回默认值

Single 和 First差别

​ Single 和 SingleOrDefault 方法大致等同于 First 和 FirstOrDefault

​ 差别在于Single将会抛出异常

ElementAt

注意:如果没有找到匹配的元素会抛出异常

如果要避免异常需要使用ElementAtOrDefault,没有找到就会返回默认值

实例:

int[] numbers = { 10, 9, 8, 7, 6 };
int secondNumber = numbers.ElementAt(2);          // 8

Count

实例:

int[] numbers = { 10, 9, 8, 7, 6 };
int count     = numbers.Count();             // 5
int evenNums = numbers.Count (n => n % 2 == 0);   // 3

Min

实例:

int min = numbers.Min();               // 6
int minRemainderAfterDivBy5 = numbers.Min(n => n % 5);       // 4

Max

实例:

int max = numbers.Max();    // 10
int maxRemainderAfterDivBy5 = numbers.Max(n => n % 5);    // 4

Average

实例:

double avg = numbers.Average();      // 8
double rms = Math.Sqrt (numbers.Average (n => n * n));

Count

注意:
DO use System.Linq.Enumerable.Any() rather than calling patents.Count()
when checking if there are more than zero items
DO use a collection’s Count property (if available)
in favor of calling the System.Linq.Enumerable.Count() method

实例:

int[] numbers = { 10, 9, 8, 7, 6 };
int count   = numbers.Count();       // 5
int evenNums = numbers.Count (n => n % 2 == 0);  // 3

Min

实例:

int min = numbers.Min();        // 6
int minRemainderAfterDivBy5 = numbers.Min(n => n % 5);    // 4

Max

实例:

int max = numbers.Max();    // 10
int maxRemainderAfterDivBy5 = numbers.Max(n => n % 5);    // 4

Average

实例:

double avg = numbers.Average();      // 8
double rms = Math.Sqrt (numbers.Average (n => n * n));

Contains

Contains returns true if the given element is present

实例:

int[] numbers = { 10, 9, 8, 7, 6 };
bool hasTheNumberNine = numbers.Contains (9);  // true

实例:

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

Any

Any returns true if the given expression is true for at least one element
Calling Any without a predicate returns true if the sequence has one or more elements

实例:

int[] numbers = { 10, 9, 8, 7, 6 };
bool hasMoreThanZeroElements = numbers.Any();  // true
bool hasOddNum = numbers.Any (n => n % 2 == 1); // true

实例:

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

实例:

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

实例:

from c in dbContext.Customers
where c.Purchases.Any (p => p.Price > 1000)
select c

All

All returns true if all elements satisfy a predicate

实例:

int[] numbers = { 10, 9, 8, 7, 6 };
bool allOddNums = numbers.All (n => n % 2 == 1);
// falseint[] numbers = { 10, 9, 8, 7, 6 };

实例:

dbContext.Customers.Where (c => c.Purchases.All (p => p.Price < 100));

Concat

运算符用于将集合添加到另一个集合
实例:

int[] seq1 = { 1, 2, 3 }, seq2 = { 3, 4, 5 };
IEnumerable<int> concat = seq1.Concat (seq2),  // { 1, 2, 3, 3, 4, 5 }

Union

执行与Concat相同的操作,但删除重复项

实例:

int[] seq1 = { 1, 2, 3 }, seq2 = { 3, 4, 5 };
IEnumerable<int> union = seq1.Union (seq2),  // { 1, 2, 3, 4, 5 }

Intersect

计算交集
实例:

IEnumerable<int> commonality = seq1.Intersect (seq2),  // { 3 }

Except

排除元素

实例:

IEnumerable<int>
difference1 = seq1.Except  (seq2),  // { 1, 2 }
difference2 = seq2.Except  (seq1);  // { 4, 5 }Deferred Exec

ToList

实例:ToList操作

var numbers = new List<int>() { 1, 2 };
List<int> timesTen = numbers
 .Select (n => n * 10) 
 .ToList();  // Executes immediately into a List<int>
numbers.Clear();
Console.WriteLine (timesTen.Count);   // Still 2
```c#
 

## TakeWhile
TakeWhile enumerates the input sequence
emitting each item until the given predicate is false
It then ignores the remaining elements

注意:不可以用于EF Core

实例:
```c#
int[] numbers   = { 3, 5, 2, 234, 4, 1 };
var takeWhileSmall = numbers.TakeWhile (n => n < 100); // { 3, 5, 2 }

SkipWhile

SkipWhile enumerates the input sequence
ignoring each item until the given predicate is false
It then emits the remaining elements

注意:不可以用于EF Core

实例:

int[] numbers   = { 3, 5, 2, 234, 4, 1 };
var skipWhileSmall = numbers.SkipWhile (n => n < 100); //{ 234, 4, 1 }

Distinct

Distinct returns the input sequence, stripped of duplicates

实例:

char[] distinctLetters = "HelloWorld".Distinct().ToArray();
string s = new string (distinctLetters);  // HeloWrd

聚合函数

image

集合操作

image

数据产生操作

image

计数操作

image

分割操作

image

Zip操作

用于将两个序列合并到一个序列中

实例:

int[] numbers = { 3, 5, 7 };
string[] words = { "three", "five", "seven", "ignored" };
IEnumerable<string> zip = 
            numbers.Zip (words, (n, w) => n + "=" + w);

Include

Entity Framework Core支持早期加载(eager loading)相关的实体数据(related entities)

早期加载可以一次性加载实体相关联的其他实体的数据,避免多次查询数据库

使用include可以实现早期加载(Eager Loading)

比如使用include进行获得学生包含年级的信息:

var studentWithGrade = context.Students
                        .Where(s => s.FirstName == "Bill")
                        .Include(s => s.Grade)
                        .FirstOrDefault();

底层的SQL代码:

SELECT TOP(1) [s].[StudentId], [s].[DoB], [s].[FirstName], [s].[GradeId],[s].[LastName], 
        [s].[MiddleName], [s.Grade].[GradeId], [s.Grade].[GradeName], [s.Grade].[Section]
FROM [Students] AS [s]
LEFT JOIN [Grades] AS [s.Grade] ON [s].[GradeId] = [s.Grade].[GradeId]
WHERE [s].[FirstName] = N'Bill'

注意:在EF6中需要写成:

var studentWithGrade = context.Students
                        .Where(s => s.FirstName == "Bill")
                        .Include("Grade")
                        .FirstOrDefault();

还可以与SQL代码混用:

var studentWithGrade = context.Students
            .FromSql("Select * from Students where FirstName ='Bill'")
            .Include(s => s.Grade)
            .FirstOrDefault();

还可以加载多个关联实体数据:

var studentWithGrade = context.Students.Where(s => s.FirstName == "Bill")
                        .Include(s => s.Grade)
                        .Include(s => s.StudentCourses)
                        .FirstOrDefault();

底部的SQL为:

SELECT TOP(1) [s].[StudentId], [s].[DoB], [s].[FirstName], [s].[GradeId], [s].[LastName], 
        [s].[MiddleName], [s.Grade].[GradeId], [s.Grade].[GradeName], [s.Grade].[Section]
FROM [Students] AS [s]
LEFT JOIN [Grades] AS [s.Grade] ON [s].[GradeId] = [s.Grade].[GradeId]
WHERE [s].[FirstName] = N'Bill'
ORDER BY [s].[StudentId]
Go

SELECT [s.StudentCourses].[StudentId], [s.StudentCourses].[CourseId]
FROM [StudentCourses] AS [s.StudentCourses]
INNER JOIN (
    SELECT DISTINCT [t].*
    FROM (
        SELECT TOP(1) [s0].[StudentId]
        FROM [Students] AS [s0]
        LEFT JOIN [Grades] AS [s.Grade0] ON [s0].[GradeId] = [s.Grade0].[GradeId]
        WHERE [s0].[FirstName] = N'Bill'
        ORDER BY [s0].[StudentId]
    ) AS [t]
) AS [t0] ON [s.StudentCourses].[StudentId] = [t0].[StudentId]
ORDER BY [t0].[StudentId]
Go

ThenInclude

使用ThenInclude方法可以加载多个层级的实体

注意ThenInclude方法必须在Include方法后调用

实例:

var student = context.Students.Where(s => s.FirstName == "Bill")
                        .Include(s => s.Grade)
                        .ThenInclude(g => g.Teachers)
                        .FirstOrDefault();

底层的SQL代码:

SELECT TOP(1) [s].[StudentId], [s].[DoB], [s].[FirstName], [s].[GradeId], [s].[LastName],
 [s].[MiddleName], [s.Grade].[GradeId], [s.Grade].[GradeName], [s.Grade].[Section]
FROM [Students] AS [s]
LEFT JOIN [Grades] AS [s.Grade] ON [s].[GradeId] = [s.Grade].[GradeId]
WHERE [s].[FirstName] = N'Bill'
ORDER BY [s.Grade].[GradeId]
Go

SELECT [s.Grade.Teachers].[TeacherId], [s.Grade.Teachers].[GradeId], [s.Grade.Teachers].[Name]
FROM [Teachers] AS [s.Grade.Teachers]
INNER JOIN (
    SELECT DISTINCT [t].*
    FROM (
        SELECT TOP(1) [s.Grade0].[GradeId]
        FROM [Students] AS [s0]
        LEFT JOIN [Grades] AS [s.Grade0] ON [s0].[GradeId] = [s.Grade0].[GradeId]
        WHERE [s0].[FirstName] = N'Bill'
        ORDER BY [s.Grade0].[GradeId]
    ) AS [t]
) AS [t0] ON [s.Grade.Teachers].[GradeId] = [t0].[GradeId]
ORDER BY [t0].[GradeId]
go

Joining(连接)

说明

IEnumerable, IEnumerable→IEnumerable

主要操作:

Join Applies a lookup strategy to match elements from two collections

emitting a flat result set

GroupJoin Similar to Join, but emits a hierarchical result set

Zip Enumerates two sequences in step (like a zipper)

applying a function over each element pair

表达式语法:

from outer-var in outer-enumerable
join inner-var in inner-enumerable on outer-key-expr equals inner-key-expr
 [ into identifier ]

注意:只可以用于比较相等,不可以用于比较不相等

如果需要比较不相等,使用select和selectMany

各种选择组合的效率比较图

image

JOIN

The Join operator performs an inner join

emitting a flat output sequence

实例:基础使用

IQueryable<string> query =
  from c in dbContext.Customers
  join p in dbContext.Purchases on c.ID equals p.CustomerID
  select c.Name + " bought a " + p.Description;

实例:连接不同的键

from x in sequenceX
join y in sequenceY on new { K1 = x.Prop1, K2 = x.Prop2 }
                equals new { K1 = y.Prop3, K2 = y.Prop4 }

实例:使用方法形式

customers.Join (                // outer collection
       purchases,                // inner collection
       c => c.ID,                // outer key selector
       p => p.CustomerID,        // inner key selector
       (c, p) => new
          { c.Name, p.Description, p.Price }    // result selector
);

Zip

IEnumerable, IEnumerable→IEnumerable

实例:基本使用

int[] numbers = { 3, 5, 7 };
string[] words = { "three", "five", "seven", "ignored" };
IEnumerable<string> zip = numbers.Zip (words, (n, w) => n + "=" + w);

实例:基本使用

string[] code = { "666", "888" };
string[] cotext = { "Panda", "Dog" };
var result = code.Zip(cotext, (c1, c2) => c2 + c1);
foreach (string item in result)
{
    Console.WriteLine(item);
}

Ordering

IEnumerable→IOrderedEnumerable

主要操作:

OrderBy, ThenBy Sorts a sequence in ascending order

OrderByDescending, Then⁠By⁠Descending Sorts a sequence in descending order

Reverse Returns a sequence in reverse order

语法:

orderby expression1 [descending] [, expression2 [descending] ... ]

实例:

IEnumerable<string> query = names.OrderBy (s => s);

实例:排序后,如果相同再次排序

IEnumerable<string> query = names.OrderBy (s => s.Length).ThenBy (s => s);

实例:排序后,如果相同再次排序多次

names.OrderBy (s => s.Length).ThenBy (s => s[1]).ThenBy (s => s[0]);

实例:降序排序,如果相同再次排序

dbContext.Purchases.OrderByDescending (p => p.Price)
                     .ThenBy (p => p.Description);
//等价于
//from p in dbContext.Purchases
//orderby p.Price descending, p.Description
//select p;

OrderBy和ThenBy的顺序
DO NOT call an OrderBy() following a prior OrderBy() method call
Use ThenBy() to sequence items by more than one value

Grouping(分组)

IEnumerable→IEnumerable<IGrouping<TKey,TElement>>

主要操作:

GroupBy Groups a sequence into subsequences

GroupBy

注意:A where after a GroupBy is equivalent to HAVING in SQL

语法:

group element-expression by key-expression

实例:

IEnumerable<IGrouping<string,string>> query =
  files.GroupBy (file => Path.GetExtension (file));
//输出
// Extension: .pdf
//   -- chapter03.pdf
//   -- chapter04.pdf
// Extension: .doc
//   -- todo.doc
//   -- menu.doc
//   -- Copy of menu.doc

实例:第二个参数用于处理元素

files.GroupBy (file => Path.GetExtension (file), file => file.ToUpper());
//输出
//Extension: .pdf
//   -- CHAPTER03.PDF
//   -- CHAPTER04.PDF
// Extension: .doc
//   -- TODO.DOC

//对应的表达式语法
// from file in files
// group file.ToUpper() by Path.GetExtension (file);

实例:分组后再排序

files.GroupBy (file => Path.GetExtension (file), file => file.ToUpper())
     .OrderBy (grouping => grouping.Key);

实例:

IEnumerable<string> query = from vote in votes
                            group vote by vote into g
                            orderby g.Count() descending
                            select g.Key;

实例:使用多个Key进行分组

from n in names
group n by new { FirstLetter = n[0], Length = n.Length };

实例:GroupBy()和组内容

//注意:这里有个ToList()方法
var result = DbContext.Person.ToList()
    .GroupBy(item => item.Age)
    .Select(item => new { Key = item.Key, it = item.Select(i => i) });

//LINQ类SQL形式
//注意:这里有个ToList()方法
// var result = from item in DbContext.Person.ToList()
//                 group item by item.Age into temp
//                 select new { Key = temp.Key, it = temp.Select(t => t) };

foreach (var item in result)
{
    //输出组名
    Console.WriteLine(item.Key);
    Console.WriteLine("=======组内容=======");
    foreach (var item2 in item.it)
    {
        Console.WriteLine(item2.Id);
        Console.WriteLine(item2.Name);
        Console.WriteLine(item2.Age);
    }
    Console.WriteLine("=======组内容=======");
}

实例:GroupBy()和Sum()

var result = DbContext.Person
            .GroupBy(item => item.Age)
            .Select(p=>new { Key = p.Key,Sum = p.Sum(p=>p.Age) });

实例:GroupBy()和Min()

var result = DbContext.Person
            .GroupBy(item => item.Age)
            .Select(p=>new { Key = p.Key,Min = p.Min(p=>p.Age) });

实例:GroupBy()和Max()

var result = DbContext.Person
            .GroupBy(item => item.Age)
            .Select(p=>new { Key = p.Key,Min = p.Max(p=>p.Age) });

实例:GroupBy()和Average()

var result = DbContext.Person
            .GroupBy(item => item.Age)
            .Select(p=>new { Key = p.Key,Min = p.Average(p=>p.Age) });

实例:GroupBy()和Count()

var result = DbContext.Person
            .GroupBy(item => item.Age)
            .Select(p=>new { Key = p.Key,Min = p.Count() });

Set Operators(集合操作)

IEnumerable, IEnumerable→IEnumerable

主要操作:

Concat Returns a concatenation of elements in each of the two sequences

Union Returns a concatenation of elements in each of the two sequences

excluding duplicates

Intersect Returns elements present in both sequences

Except Returns elements present in the first, but not the second sequence

Concat

Concat returns all the elements of the first sequence, followed by all the elements of the second

实例:

int[] seq1 = { 1, 2, 3 }, seq2 = { 3, 4, 5 };
IEnumerable<int> concat = seq1.Concat (seq2);    //  { 1, 2, 3, 3, 4, 5 }

实例:合并选择的所有子项

MethodInfo[] methods = typeof (string).GetMethods();
PropertyInfo[] props = typeof (string).GetProperties();
IEnumerable<MemberInfo> both = methods.Concat<MemberInfo> (props);

实例:过滤后再合并

var methods = typeof (string).GetMethods().Where (m => !m.IsSpecialName);
var props = typeof (string).GetProperties();
var both = methods.Concat<MemberInfo> (props);

Union

实例:

int[] seq1 = { 1, 2, 3 }, seq2 = { 3, 4, 5 };
IEnumerable<int> union  = seq1.Union  (seq2);    //  { 1, 2, 3, 4, 5 }

Intersect

Intersect returns the elements that two sequences have in common

实例:

int[] seq1 = { 1, 2, 3 }, seq2 = { 3, 4, 5 };
IEnumerable<int> commonality = seq1.Intersect (seq2),    //  { 3 }

Except

Except returns the elements in the first input sequence that are not present in the second

实例:

int[] seq1 = { 1, 2, 3 }, seq2 = { 3, 4, 5 };
IEnumerable<int>
  commonality = seq1.Intersect (seq2),    //  { 3 }
  difference1 = seq1.Except    (seq2),    //  { 1, 2 }
  difference2 = seq2.Except    (seq1);    //  { 4, 5 }

Conversion Methods(转换方法)

说明

LINQ deals primarily in sequences

in other words, collections of type IEnumerable

The conversion methods convert to and from other types of collections

主要操作

OfType Converts IEnumerable to IEnumerable

​ discarding wrongly typed elements

Cast Converts IEnumerable to IEnumerable

​ throwing an exception if there are any wrongly typed elements

ToArray Converts IEnumerable to T[]

ToList Converts IEnumerable to List

ToDictionary Converts IEnumerable to Dictionary<TKey,TValue>

ToLookup Converts IEnumerable to ILookup<TKey,TElement>

AsEnumerable Upcasts to IEnumerable

AsQueryable Casts or converts to IQueryable

OfType

OfType accept a nongeneric IEnumerable collection

and emit a generic IEnumerable sequence that you can subsequently query

Cast and OfType differ in their behavior when encountering an input element that’s of an incompatible type

Cast throws an exception

OfType ignores the incompatible element

实例:

ArrayList classicList = new ArrayList();          // in System.Collections
classicList.AddRange ( new int[] { 3, 4, 5 } );
IEnumerable<int> sequence1 = classicList.OfType<int>();

实例:出现不兼容的元素对比

DateTime offender = DateTime.Now;
classicList.Add (offender);
IEnumerable<int>
  sequence2 = classicList.OfType<int>(), // OK - ignores offending DateTime
  sequence3 = classicList.Cast<int>();   // Throws exception

Cast

Cast accept a nongeneric IEnumerable collection

and emit a generic IEnumerable sequence that you can subsequently query

Cast and OfType differ in their behavior when encountering an input element that’s of an incompatible type

Cast throws an exception

OfType ignores the incompatible element

实例:

ArrayList classicList = new ArrayList();          // in System.Collections
classicList.AddRange ( new int[] { 3, 4, 5 } );
IEnumerable<int> sequence1 = classicList.Cast<int>();

实例:出现不兼容的元素对比

DateTime offender = DateTime.Now;
classicList.Add (offender);
IEnumerable<int>
  sequence2 = classicList.OfType<int>(), // OK - ignores offending DateTime
  sequence3 = classicList.Cast<int>();   // Throws exception

ToArray

实例:

var range = Enumerable.Range(10, 10);
int[] array = range.ToArray();
foreach (int item in array)
{
    Console.WriteLine(item);
}

ToList

实例:

var range = Enumerable.Range(10, 10);
List<int> list = range.ToList();
foreach (int item in list)
{
    Console.WriteLine(item);
}

ToDictionary

实例:


ToHashSet

实例:


ToLookup

实例:

AsEnumerable

AsEnumerable upcasts a sequence to IEnumerable

实例:

AsQueryable

AsQueryable downcasts a sequence to IQueryable
实例:

Element Operators(元素运算符)

说明

IEnumerable→ TSource

主要运算符

First, FirstOrDefault

Returns the first element in the sequence, optionally satisfying a predicate

Last,LastOrDefault

Returns the last element in the sequence, optionally satisfying a predicate

Single, SingleOrDefault

Equivalent to First/FirstOrDefault

but throws an exception if there is more than one match

ElementAt, ElementAtOrDefault

Returns the element at the specified position Exception thrown

DefaultIfEmpty

Returns a single-element sequence whose value is default(TSource)

if the sequence has no elements

注意:不带default的方法,没有找到值会抛出异常

注意:带OrDefault的方法如果没有找到值会返回默认值:

null for reference type elements

false for the bool type

zero for numeric types

First

实例:

int[] numbers = { 1, 2, 3, 4, 5 };
int first   = numbers.First();           // 1
int firstEven = numbers.First (n => n % 2 == 0);   // 2

Last

实例:

int[] numbers = { 1, 2, 3, 4, 5 };
int last    = numbers.Last();            // 5
int lastEven  = numbers.Last  (n => n % 2 == 0);   // 4

Single

实例:

int[] numbers = { 1, 2, 3, 4, 5 };
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

ElementAt

注意:
Enumerable.ElementAt is written such that if the input sequence happens to implement IList,it calls IList’s indexer
Otherwise,it enumerates n times, and then returns the next element
ElementAt is not supported in EF Core

实例:

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 returns a sequence containing a single element whose value is default(TSource) if the input sequence has no elements
otherwise, it returns the input sequence unchanged

实例:

ElementAtOrDefault

Aggregation Methods(聚合方法)

说明

IEnumerable<TSource>→scalar

主要操作:
Count, LongCount Returns the number of elements in the input sequence, optionally satisfying a predicate
Min, Max Returns the smallest or largest element in the sequence
Sum, Average Calculates a numeric sum or average over elements in the sequence
Aggregate Performs a custom aggregation

Count

Count simply enumerates over a sequence, returning the number of items
LongCount does the same job as Count, but returns a 64-bit integer

实例:

int fullCount = new int[] { 5, 6, 7 }.Count();  // 3

实例:设置条件

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

LongCount

Min

实例:

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

实例:EF Core

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

实例:EF Core多次查询

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

Max

实例:

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

实例:

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

Sum

实例:

decimal[] numbers = { 3, 4, 8 };
decimal sumTotal  = numbers.Sum();        // 15

实例:带条件

int combinedLength = names.Sum (s => s.Length);  // 19

Average

Average返回类型注意:
输入类型 返回类型
decimal decimal
float float
int, long, double double

实例:

decimal[] numbers = { 3, 4, 8 };
decimal average  = numbers.Average();      // 5  (mean value)

实例:

double avg = new int[] { 3, 4 }.Average();  // 3.5

实例:EF Core结合使用

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

Aggregate

Aggregate allows you to specify a custom accumulation algorithm for implementing unusual aggregations
注意:Aggregate is not supported in EF Core and is somewhat specialized in its use cases

The first argument to Aggregate is the seed, from which accumulation starts

The second argument is an expression to update the accumulated value, given a fresh element

You can optionally supply a third argument to project the final result value from the accumulated value

实例:

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

实例:

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

实例:

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→bool

主要操作符

Contains Returns true if the input sequence contains the given element

Any Returns true if any elements satisfy the given predicate

All Returns true if all elements satisfy the given predicate

SequenceEqual Returns true if the second sequence has identical elements to the input sequence

SequenceEqual

SequenceEqual compares two sequences

To return true, each sequence must have identical elements in the identical order

You can optionally provide an equality comparer

the default is EqualityComparer.Default

Generation Methods(生成方法)

说明

void→IEnumerable

Empty Creates an empty sequence

Repeat Creates a sequence of repeating elements

Range Creates a sequence of integers

Empty

Empty manufactures an empty sequence and requires just a type argument

实例:

foreach (string s in Enumerable.Empty<string>())
  Console.Write (s);                              // <nothing>

实例:

int[][] numbers =
{
  new int[] { 1, 2, 3 },
  new int[] { 4, 5, 6 },
  null                     // this null makes the query below fail.
};
IEnumerable<int> flat = numbers
  .SelectMany (innerArray => innerArray ?? Enumerable.Empty <int>());
foreach (int i in flat)
  Console.Write (i + " ");     // 1 2 3 4 5 6

Range

Range accepts a starting index and count

实例:

foreach (int i in Enumerable.Range (5, 3))
 Console.Write (i + " ");          // 5 6 7

Repeat

Repeat accepts an element to repeat, and the number of repetitions

实例:

foreach (bool x in Enumerable.Repeat (true, 3))
 Console.Write (x + " ");          // True True True

Remove

删除数据的时候也可以带include()这样就可以实现递归删除

dbContext.Entity.Include(p => p.Instruments)

投影查询(Projection Query)

除了使用Include和ThenInclude方法进行早期加载多个实体数据
还可以使用投影查询(Projection Query)

主要操作
Select Transforms each input element with the given lambda expression
SelectMany Transforms each input element,
and then flattens and concatenates the resultant subsequences

实例:

var stud = context.Students.Where(s => s.FirstName == "Bill")
                .Select(s => new
                {
                    Student = s,
                    Grade = s.Grade,
                    GradeTeachers = s.Grade.Teachers
                })
                .FirstOrDefault();

LINQ to Object

集合查询操作符

​ 原理

​ System.Linq.Enumerable类定义集合扩展

​ 方法

​ .Where()

​ .Select()

​ .Count()

​ .Any()

​ .OrderBy()

​ .ThenBy()

LINQ to XML

命名空间

System.Xml.LINQ;

主要类型

XDocument 代表XML文档

XElement 代表XML元素

XAttribute 代表XML属性

实例

实例:使用XElement

using System;
using System.Linq;
using System.Xml.Linq;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            //LINQ对XML元素的操作
            XElement products = new XElement("Products",
                new XElement("Product",
                    new XElement("Id", 666),
                    new XElement("Title", "产品A"),
                    new XElement("Price", 66.66M)
                ),
                new XElement("Product",
                    new XElement("Id", 888),
                    new XElement("Title", "产品B"),
                    new XElement("Price", 88.88M)
                )
            );

            //筛选
            var result = from product in products.Elements()
                         where (int)product.Element("Id") == 666
                         select product;

            //测试输出结果
            foreach (XElement xElement in result)
            {
                Console.WriteLine($"{xElement.Name}-{xElement.Value}");
            }

            //wait
            Console.ReadKey();
        }
    }
}

实例:使用XAttribute

using System;
using System.Linq;
using System.Xml.Linq;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            //LINQ对XML元素的操作
            XElement products = new XElement("Products",
                new XElement("Product",
                    new XAttribute("Id", 666),
                    new XAttribute("Title", "产品A"),
                    new XAttribute("Price", 66.66M)
                ),
                new XElement("Product",
                    new XAttribute("Id", 888),
                    new XAttribute("Title", "产品B"),
                    new XAttribute("Price", 88.88M)
                )
            );

            //筛选
            var result = from product in products.Elements()
                         where (int)product.Attribute("Id") == 666
                         select product;

            //测试输出结果
            foreach (XElement xElement in result)
            {
                Console.WriteLine($"{xElement.Name}");
                foreach (XAttribute attribute in xElement.Attributes())
                {
                    Console.WriteLine($"{attribute.Name}-{attribute.Value}");
                }
            }

            //wait
            Console.ReadKey();
        }
    }
}

实例:使用XNamespace

using System;
using System.Linq;
using System.Xml.Linq;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            //定义命名空间
            XNamespace xns = "panda666.com";
            //定义元素
            XElement root = new XElement(xns + "Products",
                new XElement("Product",
                    new XAttribute("Id", 666),
                    new XAttribute("Title", "产品A"),
                    new XAttribute("Price", 66.66M)
                ),
                new XElement("Product",
                    new XAttribute("Id", 888),
                    new XAttribute("Title", "产品B"),
                    new XAttribute("Price", 88.88M)
                )
            );

            Console.WriteLine(root);
            //<Products xmlns="panda666.com">
            //< Product Id = "666" Title = "产品A" Price = "66.66" xmlns = "" />
            //< Product Id = "888" Title = "产品B" Price = "88.88" xmlns = "" />
            //</ Products >

            //wait
            Console.ReadKey();
        }
    }
}

Parallel LINQ

实例

Executing LINQ Queries in Parallel

IEnumerable<string> fileList = Directory.EnumerageFiles(
    rootDirectory, searchPattern);
var items = fileList.AsParallel().Select(
    file =>
    {
        FileInfo fileInfo = new FileInfo(file);
        return new
        {
            FileName = fileInfo.Name,
            Size = fileInfo.Length
        };
    });

实例

LINQ to Object

筛选-检测元素的长度小于三

string[] tests = new string[] { "Panda", "Cat","Dog" };
IEnumerable<string> result = Enumerable.Where(tests, t => t.Length <= 3);
//IEnumerable<string> filteredNames = names.Where (n => n.Length >= 4);
foreach (string item in result)
{
    Console.WriteLine(item);
}

筛选-检测元素包含a字符

string[] tests = new string[] { "Panda", "Cat", "Dog" };
IEnumerable<string> result = tests.Where(item => item.Contains("a"));
foreach (string item in result)
{
    Console.WriteLine(item);
}

筛选-排序

string[] tests = new string[] { "Panda", "Cat", "Dog", "Monkey" };
IEnumerable<string> result = tests.Where(item => item.Length <= 3)
    .OrderBy(item => item.Substring(0, 1))
    //.OrderByDescending(item => item.Substring(0, 1))
    .Select(item=>item);

foreach (string item in result)
{
    Console.WriteLine(item);
}

选择-获得元素的长度

string[] tests = new string[] { "Panda", "Cat" };
IEnumerable<int> result1 = tests.Select(item => item.Length);
int totalCharCount = result1.Sum();

Console.WriteLine(totalCharCount); //8
foreach (int item in result1)
{
    Console.WriteLine(item);
}

提取前三个元素

string[] tests = new string[] { "Pan", "Cat", "Pig", "Dog" };
IEnumerable<string> result = tests.Take(3);
foreach (string item in result)
{
    Console.WriteLine(item);
}

跳过指定个数的元素

string[] tests = new string[] { "Panda", "Cat", "Pig" };
IEnumerable<string> result = tests.Skip(1).Take(1);
foreach (string item in result)
{
    Console.WriteLine(item); //Cat
}

反转序列的元素顺序

string[] tests = new string[] { "Cat", "Dog", "Panda" };
IEnumerable<string> result = tests.Reverse();
foreach (string item in result)
{
    Console.WriteLine(item);
}

获得第一个元素

string[] tests = new string[] { "Panda", "Cat", "Dog" };
Console.WriteLine(tests.First());
Console.WriteLine(tests.FirstOrDefault());

获得最后一个元素

string[] tests = new string[] { "Panda", "Cat", "Dog" };
Console.WriteLine(tests.Last());
Console.WriteLine(tests.LastOrDefault());

获得指定位置的元素

string[] tests = new string[] { "Panda", "Cat", "Dog" };
Console.WriteLine(tests.ElementAt(1));
Console.WriteLine(tests.ElementAtOrDefault(0));

获得元素中的最大值

int[] tests = new int[] { 1, 2, 3, 4, 5, 6 };
Console.WriteLine(tests.Max());

获得元素中的最小值

int[] tests = new int[] { 1, 2, 3, 4, 5, 6 };
Console.WriteLine(tests.Min());

获得元素中的平均值

int[] tests = new int[] { 1, 2, 3, 4, 5, 6 };
Console.WriteLine(tests.Average());

获得元素中的和

int[] tests = new int[] { 1, 2, 3, 4, 5, 6 };
Console.WriteLine(tests.Sum());

获得元素个数

int[] tests = new int[] { 1, 2, 3, 4, 5, 6 };
Console.WriteLine(tests.Count());

跨Lambda表达式的变量

string[] names = { "Tom", "Dick", "Harry", "Mary", "Jay" };
IEnumerable<string> outerQuery = names
  .Where (n => n.Length == names.OrderBy (n2 => n2.Length)
                                .Select  (n2 => n2.Length).First());
// Tom, Jay

检测是否包含某元素

int[] tests = new int[] { 1, 2, 3, 4, 5, 6 };
Console.WriteLine(tests.Contains(1));    //true
Console.WriteLine(tests.Contains(10));   //false

检测某个元素是否符合某个条件

int[] tests = new int[] { 1, 2, 3, 4, 5, 6 };
Console.WriteLine(tests.Any(item=>item > 5));   //True

检测全部元素是否符合某个条件

int[] tests = new int[] { 1, 2, 3, 4, 5, 6 };
Console.WriteLine(tests.All(item => item > 0)); //True

连接序列

int[] seq1 = new int[] { 1, 2, 3 };
int[] seq2 = new int[] { 3, 4, 5, 6 };
IEnumerable<int> result1 = seq1.Concat(seq2);
foreach (int item in result1)
{
    Console.Write(item);
}

使用into定义变量

var query = from n in names
                select new
                {
                    Original = n,
                    Vowelless = n.item
                }
                into temp
                where temp.Vowelless.Length > 2
                select temp.Original;

求两个序列的并集

int[] seq1 = new int[] { 1, 2, 3 };
int[] seq2 = new int[] { 3, 4, 5, 6 };
IEnumerable<int> result2 = seq1.Union(seq2);
foreach (int item in result2)
{
    Console.Write(item);
}

筛选出长度大于3的元素

string[] tests = new string[] { "Panda", "Cat", "Dog", "Pig" };
IEnumerable<string> result = from item in tests
                                where item.Length > 3
                                select item;

foreach (string item in result)
{
    Console.WriteLine(item); //Panda
}

LINQ基本筛选

using System;
using System.Collections.Generic;
using System.Linq;

namespace Panda
{
    class Panda
    {
        static void Main(string[] args)
        {
            int[] numbers = { 1, 2, 3, 4, 5, 6, 7 }; //对象集合
            IEnumerable<int> minNumber = from i in numbers
                                        where i <= 3
                                        select i;

            foreach (int item in minNumber)
            {
                Console.WriteLine(item);
            }

            Console.ReadKey();
        }
    }
}

LINQ操作数组

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApp3
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] i = new int[] { 1, 2, 3, 4 };
            IEnumerable<int> a = from cc in i
                                 where cc > 2
                                 orderby cc
                                 select cc;
            foreach (var item in a)
            {
                Console.WriteLine(item);
            }
            Console.ReadKey();
        }
    }
}

LINQ数组筛选并排序

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApp1
{

    class Program
    {
        static void Main(string[] args)
        {
            int[] datas = new int[]{
                1,2,3,4,5,6,7,8,9
            };

            var qureyResult = from item in datas
                              where item % 2 == 0
                              orderby item descending
                              select item;
            
            foreach (int item in qureyResult)
            {
                Console.WriteLine(item);
            }

            Console.ReadKey();
        } 
    }
}

LINQ数组筛选并排序(方法形式)

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApp1
{

    class Program
    {
        static void Main(string[] args)
        {
            int[] datas = new int[]{
                1,2,3,4,5,6,7,8,9
            };

            var qureyResult = datas.Where(x => x % 2 == 0).OrderBy(x => -x);
            
            foreach (int item in qureyResult)
            {
                Console.WriteLine(item);
            }

            Console.ReadKey();
        } 
    }
}

LINQ多重排序

使用了OrderBy之后再用ThenBy

var query = names
 .Where(name => name.Length > 4)
 .OrderBy(name => name.Length)
 .ThenBy(name => name);

LINQ数组筛选(多条件并)

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] datas = new int[]{
                1,2,3,4,5,6,7,8,9
            };

            var qureyResult = from item in datas
                              where item % 2 == 0 && item % 3 == 0
                              orderby item descending
                              select item;

            foreach (int item in qureyResult)
            {
                Console.WriteLine(item);
            }

            Console.ReadKey();
        }
    }
}

LINQ数组筛选(多条件并)(方法形式)

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] datas = new int[]{
                1,2,3,4,5,6,7,8,9
            };

            var qureyResult = datas.Where(x => (x % 2 == 0 && x % 3 == 0))
                                    .OrderBy(x => -x);

            foreach (int item in qureyResult)
            {
                Console.WriteLine(item);
            }

            Console.ReadKey();
        }
    }
}

LINQ数组筛选(多条件或)

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] datas = new int[]{
                1,2,3,4,5,6,7,8,9
            };

            var qureyResult = from item in datas
                              where item % 2 == 0 || item % 3 == 0
                              orderby item descending
                              select item;

            foreach (int item in qureyResult)
            {
                Console.WriteLine(item);
            }

            Console.ReadKey();
        }
    }
}

LINQ数组筛选(多条件或)(方法形式)

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] datas = new int[]{
                1,2,3,4,5,6,7,8,9
            };

            var qureyResult = datas.Where(x => (x % 2 == 0 || x % 3 == 0))
                                    .OrderBy(x => -x);

            foreach (int item in qureyResult)
            {
                Console.WriteLine(item);
            }

            Console.ReadKey();
        }
    }
}

LINQ分组

使用GroupBy()方法。返回值为IGrouping<TKey,TSource>类型的泛型。IGrouping对象的形式返回。IGrouping是一个继承自IEnumerable的接口。IGrouping中
Key属性表示这一组的分组数据的值。

LINQ分组

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApp3
{
    /// <summary>
    /// 用于查询的对象
    /// </summary>
    class Car
    {
        public string CarName;
        public decimal Price;
        public string ProductSeries;
    }
    class Program
    {
        static void Main(string[] args)
        {
            //实例化一个泛型集合
            List<Car> Garage = new List<Car>
            {
                new Car{CarName = "C1", Price = 666M, ProductSeries = "T1"},
                new Car{CarName = "C2", Price = 777M, ProductSeries = "T3"},
                new Car{CarName = "C3", Price = 888M, ProductSeries = "T2"},
                new Car{CarName = "C4", Price = 999M, ProductSeries = "T1"},
                new Car{CarName = "C5", Price = 999M, ProductSeries = "T1"},
                new Car{CarName = "C6", Price = 999M, ProductSeries = "T3"}
            };

            //对泛型集合进行LINQ查询
            var queryResult = from item in Garage
                     orderby item.Price
                     group item by item.ProductSeries;

            //遍历输出集合
            foreach (var g in queryResult)
            {
                //输出组名
                Console.WriteLine("==== {0} =====", g.Key);
                //输出组内容
                foreach (Car car in g)
                {
                    Console.WriteLine("The CarName is {0} and Price is {1}", car.CarName, car.Price);
                }
            }

            //wait
            Console.ReadKey();
        }
    }
}

LINQ分组(方法形式)

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApp3
{
    /// <summary>
    /// 用于查询的对象
    /// </summary>
    class Car
    {
        public string CarName;
        public decimal Price;
        public string ProductSeries;
    }
    class Program
    {
        static void Main(string[] args)
        {
            //实例化一个泛型集合
            List<Car> Garage = new List<Car>
            {
                new Car{CarName = "C1", Price = 666M, ProductSeries = "T1"},
                new Car{CarName = "C2", Price = 777M, ProductSeries = "T3"},
                new Car{CarName = "C3", Price = 888M, ProductSeries = "T2"},
                new Car{CarName = "C4", Price = 999M, ProductSeries = "T1"},
                new Car{CarName = "C5", Price = 999M, ProductSeries = "T1"},
                new Car{CarName = "C6", Price = 999M, ProductSeries = "T3"}
            };

            //对泛型集合进行LINQ查询
            var queryResult = Garage.OrderBy(x => x.Price)
                .GroupBy(x => x.ProductSeries);

            //遍历输出集合
            foreach (var g in queryResult)
            {
                //输出组名
                Console.WriteLine("==== {0} =====", g.Key);
                //输出组内容
                foreach (Car car in g)
                {
                    Console.WriteLine("The CarName is {0} and Price is {1}", car.CarName, car.Price);
                }
            }

            //wait
            Console.ReadKey();
        }
    }
}

LINQ分组实例

根据年龄分组,获取每组人数、最高工资、平均工资。

IEnumerable<IGrouping<int, Employee>> items = list.GroupBy(e => e.Age);

LINQ对分组再进行筛选

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApp3
{
    /// <summary>
    /// 用于查询的对象
    /// </summary>
    class Car
    {
        public string CarName;
        public decimal Price;
        public string ProductSeries;
    }
    class Program
    {
        static void Main(string[] args)
        {
            //实例化一个泛型集合
            List<Car> Garage = new List<Car>
            {
                new Car{CarName = "C1", Price = 666M, ProductSeries = "T1"},
                new Car{CarName = "C2", Price = 777M, ProductSeries = "T3"},
                new Car{CarName = "C3", Price = 888M, ProductSeries = "T2"},
                new Car{CarName = "C4", Price = 999M, ProductSeries = "T1"},
                new Car{CarName = "C5", Price = 999M, ProductSeries = "T1"},
                new Car{CarName = "C6", Price = 999M, ProductSeries = "T3"}
            };

            //对泛型集合进行LINQ查询
            var queryResult = from item in Garage
                              orderby item.Price
                              group item by item.ProductSeries into tempGroup
                              where tempGroup.Count() >= 2
                              select tempGroup;

            //遍历输出集合
            foreach (var g in queryResult)
            {
                //输出组名
                Console.WriteLine("==== {0} =====", g.Key);
                //输出组内容
                foreach (Car car in g)
                {
                    Console.WriteLine("The CarName is {0} and Price is {1}", car.CarName, car.Price);
                }
            }

            //wait
            Console.ReadKey();
        }
    }
}

LINQ使用join

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApp3
{
    /// <summary>
    /// 汽车类
    /// </summary>
    class Car
    {
        public string CarName;
        public decimal Price;
        public string ProductSeries;
    }

    /// <summary>
    /// 汽车系列类
    /// </summary>
    class ProductSeries
    {
        public string SeriesCode;
        public string SeriesName;
    }
    class Program
    {
        static void Main(string[] args)
        {
            //实例化汽车类的泛型集合
            List<Car> garage = new List<Car>
            {
                new Car{CarName = "C1", Price = 666M, ProductSeries = "T1"},
                new Car{CarName = "C2", Price = 777M, ProductSeries = "T3"},
                new Car{CarName = "C3", Price = 888M, ProductSeries = "T2"},
                new Car{CarName = "C4", Price = 999M, ProductSeries = "T1"},
                new Car{CarName = "C5", Price = 999M, ProductSeries = "T1"},
                new Car{CarName = "C6", Price = 999M, ProductSeries = "T3"},
            };

            //实例化系列类的泛型集合
            List<ProductSeries> productSeries = new List<ProductSeries>
            {
                new ProductSeries{SeriesCode = "T1", SeriesName = "豪华系列"},
                new ProductSeries{SeriesCode = "T2", SeriesName = "中级系列"},
                new ProductSeries{SeriesCode = "T3", SeriesName = "普通系列"}
            };

            //进行LINQ查询
            var queryResult = from car in garage
                              join series in productSeries
                              on car.ProductSeries equals series.SeriesCode
                              orderby Convert.ToInt32(series.SeriesCode[1]) descending
                              select new { series.SeriesName, car.CarName, car.Price };

            //遍历输出集合
            foreach (var item in queryResult)
            {
                Console.WriteLine("{0} - {1} - {2}",item.SeriesName, item.CarName, item.Price);
            }

            //wait
            Console.ReadKey();
        }
    }
}

LINQ使用join(方法形式)

LINQ计算结果集个数

using System;
using System.Linq;
using System.Collections.Generic;

namespace ConsoleApp3
{

    class Program
    {
        
        static void Main(string[] args)
        {
            int[] numbers = new int[]
            {
                1,2,3,4,5,6,7
            };

            //结合使用
            int queryResult = (from n in numbers
                               where n < 3
                               select n).Count();

            Console.WriteLine(queryResult);

            //wait
            Console.ReadKey();
        }
    }
}

LINQ计算结果集个数(方法形式)

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApp1
{

    class Program
    {
        static void Main(string[] args)
        {
            int[] datas = new int[]{
                1,2,3,4,5,6,7,8,9
            };

            var qureyResult = from item in datas
                              where item % 2 == 0
                              orderby item descending
                              select item;
            //计算个数
            int count = qureyResult.Count();
            Console.WriteLine(count);
            Console.ReadKey();
        }
    }
}

LINQ计算和

using System;
using System.Linq;
using System.Collections.Generic;

namespace ConsoleApp3
{

    class Program
    {
        
        static void Main(string[] args)
        {
            int[] numbers = new int[]
            {
                1,2,3,4,5,6,7
            };

            //计算和
            int queryResult = (from n in numbers
                               where n < 3
                               select n).Sum();

            Console.WriteLine(queryResult);

            //wait
            Console.ReadKey();
        }
    }
}

LINQ计算平均数

using System;
using System.Linq;
using System.Collections.Generic;

namespace ConsoleApp3
{

    class Program
    {
        
        static void Main(string[] args)
        {
            int[] numbers = new int[]
            {
                1,2,3,4,5,6,7
            };

            //计算平均数
            double queryResult = (from n in numbers
                               where n < 3
                               select n).Average();

            Console.WriteLine(Math.Round(queryResult,2));

            //wait
            Console.ReadKey();
        }
    }
}

LINQ计算最大值

using System;
using System.Linq;
using System.Collections.Generic;

namespace ConsoleApp3
{

    class Program
    {
        
        static void Main(string[] args)
        {
            int[] numbers = new int[]
            {
                1,2,3,4,5,6,7
            };

            //计算最大值
            int queryResult = (from n in numbers
                               where n < 3
                               select n).Max();

            Console.WriteLine(queryResult);

            //wait
            Console.ReadKey();
        }
    }
}

LINQ计算最小值

using System;
using System.Linq;
using System.Collections.Generic;

namespace ConsoleApp3
{

    class Program
    {
        
        static void Main(string[] args)
        {
            int[] numbers = new int[]
            {
                1,2,3,4,5,6,7
            };

            //计算最小值
            int queryResult = (from n in numbers
                               where n < 3
                               select n).Min();

            Console.WriteLine(queryResult);

            //wait
            Console.ReadKey();
        }
    }
}

LINQ去除重复数据

using System;
using System.Linq;
using System.Collections.Generic;

namespace ConsoleApp3
{

    class Program
    {
        
        static void Main(string[] args)
        {
            //测试数据
            int[] testData = new int[]
            {
                1,1,2,2,3,4,5,6,7,8
            };

            //查询
            var queryResult = (from n in testData
                               where n < 3
                               select n).Distinct();

            //输出结果
            foreach (var item in queryResult)
            {
                Console.WriteLine(item);
            }

            //wait
            Console.ReadKey();
        }
    }
}

LINQ大小写转换

using System;
using System.Linq;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            string[] words = new string[]{
                "Panda","Dog","Monkey","Donkey"
            };

            //转为大写
            var result = from word in words
                         select word.ToUpper();
            //转为小写
            var result2 = from word in words
                          select word.ToLower();

            //测试
            foreach (var item in result)
            {
                Console.WriteLine(item);
            }

            //测试
            foreach (var item in result2)
            {
                Console.WriteLine(item);
            }

            Console.ReadKey();
        }
    }
}

LINQ使用let定义中间变量

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApp3
{
    class Program
    {
        static void Main(string[] args)
        {
            string[] animals = new string[]
            {
                "Panda","Monkey","Dog","Cat"
            };

            var queryResult = from animal in animals
                              let tempChars = animal.Split('n')
                              from item in tempChars
                              select item.ToUpper();

            foreach (string c in queryResult)
            {
                Console.WriteLine(c);
            }

            Console.ReadKey();
        }
    }
}

LINQ操作泛型集合

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApp3
{
    /// <summary>
    /// 用于查询的对象
    /// </summary>
    class Car
    {
        public string CarName;
        public decimal Price;
    }
    class Program
    {
        static void Main(string[] args)
        {
            //实例化一个泛型集合
            List<Car> Garage = new List<Car>
            {
                new Car{CarName = "a", Price = 666M},
                new Car{CarName = "b", Price = 777M},
                new Car{CarName = "c", Price = 888M},
                new Car{CarName = "d", Price = 999M}
            };

            //对泛型集合进行LINQ查询
            var ss = from item in Garage
                     where item.Price >= 888M
                     orderby item.Price
                     select item;

            //遍历输出集合的子项
            foreach (var item in ss)
            {
                Console.WriteLine("The CarName is {0} and Price is {1}", item.CarName, item.Price);
            }

            //wait
            Console.ReadKey();
        }
    }
}

LINQ操作非泛型集合

using System;
using System.Collections;
using System.Linq;

namespace ConsoleApp3
{
    /// <summary>
    /// 用于查询的对象
    /// </summary>
    class Car
    {
        public string CarName;
        public decimal Price;
    }
    class Program
    {
        static void Main(string[] args)
        {
            //实例化一个泛型集合
            ArrayList Garage = new ArrayList
            {
                new Car{CarName = "a", Price = 666M},
                new Car{CarName = "b", Price = 777M},
                new Car{CarName = "c", Price = 888M},
                new Car{CarName = "d", Price = 999M}
            };
            //使用.OfType<T>()转换为泛型集合进行处理
            //.OfType<T>()同时具有筛选功能,筛选出T类型的子项
            var GarageEnum = Garage.OfType<Car>();
            //对泛型集合进行LINQ查询
            var ss = from item in GarageEnum
                     where item.Price >= 888M
                     orderby item.Price
                     select item;

            //遍历输出集合的子项
            foreach (var item in ss)
            {
                Console.WriteLine("The CarName is {0} and Price is {1}", item.CarName, item.Price);
            }
            Console.ReadKey();
        }
    }
}

LINQ查询结果转为数组

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApp3
{
    /// <summary>
    /// 用于查询的对象
    /// </summary>
    class Car
    {
        public string CarName;
        public decimal Price;
    }
    class Program
    {
        static void Main(string[] args)
        {
            //实例化一个泛型集合
            List<Car> Garage = new List<Car>
            {
                new Car{CarName = "a", Price = 666M},
                new Car{CarName = "b", Price = 777M},
                new Car{CarName = "c", Price = 888M},
                new Car{CarName = "d", Price = 999M}
            };
            //对泛型集合进行LINQ查询
            var linqResult = from item in Garage
                     where item.Price >= 888M
                     orderby item.Price
                     select item;
            //转为数组
            Car[] searchedCar = linqResult.ToArray<Car>();
            //遍历输出集合的子项
            foreach (var item in searchedCar)
            {
                Console.WriteLine("The CarName is {0} and Price is {1}", item.CarName, item.Price);
            }
            Console.ReadKey();
        }
    }
}

LINQ查询结果转为泛型集合List

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApp3
{
    /// <summary>
    /// 用于查询的对象
    /// </summary>
    class Car
    {
        public string CarName;
        public decimal Price;
    }
    class Program
    {
        static void Main(string[] args)
        {
            //实例化一个泛型集合
            List<Car> Garage = new List<Car>
            {
                new Car{CarName = "a", Price = 666M},
                new Car{CarName = "b", Price = 777M},
                new Car{CarName = "c", Price = 888M},
                new Car{CarName = "d", Price = 999M}
            };
            //对泛型集合进行LINQ查询
            var linqResult = from item in Garage
                             where item.Price >= 888M
                             orderby item.Price
                             select item;
            //转为List<Car>
            List<Car> searchedCar = linqResult.ToList<Car>();
            //遍历输出集合的子项
            foreach (var item in searchedCar)
            {
                Console.WriteLine("The CarName is {0} and Price is {1}", item.CarName, item.Price);
            }
            Console.ReadKey();
        }
    }
}

LINQ查询多from

string[] animals = new string[]
{
    "Panda,Dog,Cat,Monkey,Donkey",
    "Duck,Cow,Forg,Rabbit,Mouse"
};
//查询
var queryResult = from item in animals
                    from sub in item.Split(',')
                    select sub;
//输出
foreach (string item in queryResult)
{
    Console.WriteLine(item);
}

查找指定的记录使用Key(方法)(Entitty)

using(PandaContext db = new PandaContext())
{
    db.Products.Find(1);
}

查找指定的第一条记录使用条件(方法)

//查找第一个数据,没有找到抛出异常
var queryResult1 = products.First();
//查找第一个数据(并筛选),没有找到抛出异常
var queryResult2 = products.First(x=>x.ProductId < 2);
//查找第一个数据,没有找到返回null
var queryResult3 = products.FirstOrDefault();
//查找第一个数据(并筛选),没有找到返回null
var queryResult4 = products.FirstOrDefault(x => x.ProductId < 2);

查找条件筛选(方法)

var queryResult = products.Where(x => x.ProductName == "Panda");

排序(方法)

//升序排序
var queryResult1 = products.OrderBy(x => x.ProductId);
//降序排序
var queryResult2 = products.OrderByDescending(x => x.ProductId);
再次排序(方法)
注意:必须在OrderBy或OrderByDescending后使用
//再次升序排序
var queryResult1 = products.OrderBy(x => x.ProductId).ThenBy(x=>x.ProductName);
//再次降序排序
var queryResult2 = products.OrderByDescending(x => x.ProductId).ThenByDescending(x=>x.ProductName);

降序排序

var query = db.Person.OrderByDescending(x => x.LastName);

指定提取条数

指定从数据库提出的数据条数
注意:并不一定返回指定的条数,有可能查询的条数少于指定的提取的条数

var queryResult = products.Where(x => x.ProductId < 100).Take(10);

指定提取条数(条件)

//返回指定的元素(条件)
IEnumerable<string> result1 = testData.TakeWhile(x=>x.Contains("Panda"));

条件测试(任意一个条件满足)

//任意一个满足条件返回true,否则返回false
bool result1 = testData.Any(x => x.Length > 2);

条件测试(所有条件都满足)

//所有条件都满足返回true,否则返回false
bool result2 = testData.All(x => x.Length > 2);

获得数量(满足条件)

//获得数量(满足条件)
int result1 = testData.Count(x => x.Length > 2);
获得数量(满足条件)(long类型)
//获得数量(满足条件)(long类型)
long result2 = testData.LongCount(x => x.Length > 2);

将元素转为指定类型

//将元素转为指定类型
IEnumerable<string> result = testData.Cast<string>();

foreach (string item in result)
{
    Console.WriteLine(item);
}

获得指定位置的元素

//获得指定位置的元素
//注意:如果没有找到,返回类型的默认值
IEnumerable<string> result1 = testData.DefaultIfEmpty();
//指定没有找到的情况下的默认值
IEnumerable<string> result2 = testData.DefaultIfEmpty("Panda");

foreach (var item in result1)
{
    Console.WriteLine(item);
}

foreach (var item in result2)
{
    Console.WriteLine(item);
}

获得指定索引处的元素

//获得指定索引处的元素
//注意:这个方法没有找到元素的情况下会抛出异常
string result1 = testData.ElementAt(0);

//没有找到情况下,返回类型的默认值
string result2 = testData.ElementAtOrDefault(10);

获得最后一个元素

//获得最后一个元素
string result1 = testData.Last();
//获得最后一个元素(并筛选)
string result2 = testData.Last(x => x.Length > 2);
//获得最后一个元素,没有找到返回默认值
string result3 = testData.LastOrDefault();
//获得最后一个元素,没有找到返回默认值(并筛选)
string result4 = testData.LastOrDefault(x=>x.Length > 2);

返回唯一元素

//返回唯一元素
//返回只有一个元素的序列的元素
//注意:如果不是只有一个元素将抛出异常
string result1 = testData.Single();
//指定条件
//注意:如果不是只有一个元素将抛出异常
string result2 = testData.Single(x => x.Length < 2);
//没有找到返回类型的默认值
string result3 = testData.SingleOrDefault();
string result4 = testData.SingleOrDefault(x => x.Length > 2);

连接2个序列

//连接2个序列
IEnumerable<string> result = testData.Concat(testData2);

计算差集

//计算差集
var result = testData.Except(testData2);

计算交集

//计算交集
var result = testData.Intersect(testData2);

计算并集

//计算并集
var result = testData.Union(testData2);

比较集合相等

//比较集合相等
bool result = testData.SequenceEqual(testData2);

跳过指定的元素

//跳过指定的元素
//跳过指定的元素(个数)
IEnumerable<string> result1 = testData.Skip(2);
//跳过指定的元素(条件)
IEnumerable<string> result2 = testData.SkipWhile(x => x.Contains("Panda"));

是否至少有一条数据

有可能比Count()效率高。

bool b1 = list.Any(e => e.Salary > 8000);
bool b2 = list.Where(e => e.Salary > 8000).Any();

有且只有一条满足要求的数据

list.Single(e => e.Age > 15);

最多只有一条满足要求的数据

list.SingleOrDefault(e => e.Age > 15);

返回第一条

list.Where(e => e.Salary > 8000).First();

返回第一条或者默认值

list.Where(e => e.Salary > 8000).FirstOrDefault();

对数据正序排序

list.OrderBy(e => e.Age);

倒序排序

list.OrderByDescending(e => e.Age);

多规则排序

可以在Order()、OrderByDescending()后继续写ThenBy()、ThenByDescending()

实例:优先按照Age排序,如果Age相同再按照Salary排序。

list.OrderBy(e => e.Age).ThenByDescending(e => e.Salary);

计算三个数值中的最大值

int i1 = 1;
int i2 = 101;
int i3 = 100;
//计算最大值
int result = new[] { i1, i2, i3 }.Max();

统计字符出现次数

统计一个字符串中每个字母出现的频率(忽略大小写),然
后按照从高到低的顺序输出出现频率高于2次的单词和其出
现的频率。

var items = s.Where(c => char.IsLetter(c))	  //过滤非字母
			.Select(c=>char.ToLower(c))		//大写字母转换为小写
			.GroupBy(c=>c)					//根据字母进行分组
			.Where(g=>g.Count()>2)			//过滤掉出现次数<=2
			OrderByDescending(g=>g.Count())	 //按次数排序
			.Select(g=>new { Char=g.Key,Count=g.Count() });
posted @ 2022-09-30 08:37  重庆熊猫  阅读(289)  评论(0编辑  收藏  举报