【.NET Core】Linq查询运算符(三)

简介: 笔记

一、概述


查询运算符是组成Linq模式的方法。这些方法中的大多数都作用于序列;其中序列指其类型实现IEnumberable<T>接口或IQueryable<T>接口的对象。标准查询运算符提供包括筛选、投影、集合、排序等查询功能。

查询运算符包含两组,一组作用于类型IEnumberable<T>的对象,另一组作用于类型IQueryable<T>的对象。

《Linq查询运算符(一)》详细介绍了筛选数据、投影运算、设置运算 、数据排序、限定符运算及数据分区等

《Linq查询运算符(二)》详细介绍了生成运算、相等运算、元素运算、转换数据类型等,

本文将继续介绍Linq运算符串联运算、聚合运算、联接运算及数据分组。


二、串联运算


2.1 Enumerable.Concat

连接两个序列。

public static System.Collections.Generic.IEnumerable<TSource> Concat<TSource> (this System.Collections.Generic.IEnumerable<TSource> first, System.Collections.Generic.IEnumerable<TSource> second);

参数类型

TSource:输入序列中的元素的类型。


参数

first IEnumerable

要连接的第一个序列

second IEnumerable

要与第一个序列连接的序列


返回

一个包含两个输入序列的连接元素的IEnumerable

Person[] parameters = new Person[]
{
   new Person() { Id = 1, Code = "052", Name = "正一郎" },
   new Person() { Id = 2, Code = "028", Name = "正贰郎" },
   new Person() { Id = 3, Code = "020", Name = "正叁郎" }
};
Person[] parameters1 = new Person[]{
   new Person() { Id = 1, Code = "030", Name = "次一郎" },
   new Person() { Id = 2, Code = "031", Name = "次二郎" },
   new Person() { Id = 3, Code = "032", Name = "次三郎" }
};
var three= parameters.Select(p => p.Name).Concat(parameters1.Select(p=>p.Name));
foreach (var person in three) 
{
   Console.WriteLine(person);
}

输出结果

正一郎
正次郎
誠三郎
次一郎
次贰郎
次叁郎


三、聚合运算


聚合运算从值的集合中计算出单个值。


3.1 Aggregate

对序列应用累加器函数。 将指定的种子值用作累加器的初始值,并使用指定的函数选择结果值。

public static TResult Aggregate<TSource,TAccumulate,TResult> (this System.Linq.IQueryable<TSource> source, TAccumulate seed, System.Linq.Expressions.Expression<Func<TAccumulate,TSource,TAccumulate>> func, System.Linq.Expressions.Expression<Func<TAccumulate,TResult>> selector);


类型参数

TSource source的元素类型。

TAccumulate 累加器值的类型。

TResult 结果值的类型。


参数

source 要对其进行聚合的序列

seed TAccumulate累加器的初始值

func Expression<Func<TAccumulate,TSource,TAccumulate>>

要对每个元素调用的累加器函数

selector Expression<Func<TAccumulate,TResult>>

将累加器的最终值转换为结果值的函数。


返回

TResult

已转换的累加器最终值。

string[] fruits = { "apple", "mango", "orange", "passionfruit", "grape" };
string result=  fruits.AsEnumerable().Aggregate("", (current, next) => current + " " + next+"   ");
Console.WriteLine(result);

运行结果

apple    mango    orange    passionfruit    grape


3.2 Average

计算可以为 null 的数值序列的平均值,这些值可通过对输入序列的每个元素调用转换函数获得。

定义

public static T Average (this System.Collections.Generic.IEnumerable<T> source);

T为数值类型

string[] numbers = { "100", "98", "50","2" };
double average = numbers.Average(num => long.Parse(num));
Console.WriteLine("The average is {0}.", average);

运行结果

The average is 62.5.


3.3 Count

返回指定的序列中满足条件的元素数量。

定义


public static int Count<TSource> (this System.Collections.Generic.IEnumerable<TSource> source);
string[] fruits = { "apple", "mango", "orange", "passionfruit", "grape" };
int fruitCount = fruits.Count();
Console.WriteLine($"水果的种类:{fruitCount}.");
int fruitCount2 = fruits.Count(e=>e.IndexOf('m')==0);
Console.WriteLine($"水果的种类:{fruitCount2}.");

运行结果

水果的种类:5.
水果的种类:1.


3.4 LongCount

返回序列中的元素数量的Int64

定义

public static long LongCount<TSource> (this System.Collections.Generic.IEnumerable<TSource> source, Func<TSource,bool> predicate);
string[] fruits = { "apple", "mango", "orange", "passionfruit", "grape" };
long fruitCount = fruits.LongCount();
Console.WriteLine($"水果的种类:{fruitCount}.");
long fruitCount2 = fruits.LongCount(e=>e.IndexOf('m')==0);
Console.WriteLine($"水果的种类:{fruitCount2}.");

运行结果

水果的种类:5.
水果的种类:1.


3.5 Max 或 MaxBy

确定集合中的最大值

定义

public static TSource? Max<TSource> (this System.Collections.Generic.IEnumerable<TSource> source, System.Collections.Generic.IComparer<TSource>? comparer);
string[] fruits = { "apple", "mango", "orange", "passionfruit", "grape" };
string[] numbers = { "100", "98", "50","2" };
int maxInt = numbers.Max(x => int.Parse(x));
Console.WriteLine(maxInt);
int maxLength = fruits.Max(x => x.Length);
Console.WriteLine(maxLength);

运行结果

100
12


3.6 Min 或 MinBy

确定集合中的最下值

Min<TSource>(IEnumerable<TSource>, Func<TSource,Double>)
string[] fruits = { "apple", "mango", "orange", "passionfruit", "grape" };
string[] numbers = { "100", "98", "50","2" };
int minInt = numbers.Min(x => int.Parse(x));
Console.WriteLine(minInt);
int minLength = fruits.Min(x => x.Length);
Console.WriteLine(minLength);

运行结果

2
5


3.7 Sum

对集合中的值求和。如果 source 不包含任何元素,则此方法返回零。

定义

Sum<TSource>(IEnumerable<TSource>, Func<TSource,Single>)Sum<TSource>(IEnumerable<TSource>, Func<TSource,Single>)


四、聚合运算


联接两个数据源就是将一个数据源中的对象与另一个数据源中具有相同公共属性的对象相关联。


当查询所有面向的数据源相互之间具有无法直接领会的关系时,Join就成为一项重要的运算。在面向对象的编程中,这可能意味着建模对象之间进行关联。Linq框架中提供的join方法包括Join和GroupJoin。这些方法执行同等联接。既根据2个数据源的键是否相等来匹配这2个数据源的联接。


定义测试测试类Product

class Product
{
    public string? Name { get; set; }
    public int CategoryId { get; set; }
}

定义测试测试类Category

class Category
{
    public int Id { get; set; }
    public string? CategoryName { get; set; }
}


4.1 Join

根据键选择器函数Join两个序列并提取值对。

表达式语法

Join … in … on … equals …

List<Product> products = new List<Product>
{
     new Product { Name = "Cola", CategoryId = 0 },
     new Product { Name = "Tea", CategoryId = 0 },
     new Product { Name = "Apple", CategoryId = 1 },
     new Product { Name = "Kiwi", CategoryId = 1 },
     new Product { Name = "Carrot", CategoryId = 2 } 
};
List<Category> categories = new List<Category> {
     new Category { Id = 0, CategoryName = "Beverage" },
     new Category { Id = 1, CategoryName = "Fruit" },
     new Category { Id = 2, CategoryName = "Vegetable" }
};
var query = from product in products
            join category in categories on product.CategoryId equals category.Id
            select new { product.Name,product.CategoryId, category.CategoryName };
foreach (var item in query)
{
     Console.WriteLine($"{item.Name} - {item.CategoryName}");
}

运行结果

Cola - Beverage
Tea - Beverage
Apple - Fruit
Kiwi - Fruit
Carrot - Vegetable


4.1 GroupJoin

根据键选择器函数Join两个序列,并对每个元素的结果匹配项进行分组。

表达式语法

join … in … on … equals …

List<Product> products = new List<Product>
{
       new Product { Name = "Cola", CategoryId = 0 },
       new Product { Name = "Tea", CategoryId = 0 },
       new Product { Name = "Apple", CategoryId = 1 },
       new Product { Name = "Kiwi", CategoryId = 1 },
       new Product { Name = "Carrot", CategoryId = 2 } 
};
List<Category> categories = new List<Category> {
     new Category { Id = 0, CategoryName = "Beverage" },
     new Category { Id = 1, CategoryName = "Fruit" },
     new Category { Id = 2, CategoryName = "Vegetable" }
};
var productGroups = from category in categories
                    join product in products on category.Id equals product.CategoryId
                    into productGroup select productGroup;
foreach (IEnumerable<Product> productGroup in productGroups)
{
    Console.WriteLine("Group");
    foreach (Product product in productGroup)
    {
       Console.WriteLine($"{product.Name,8}");
    }
}


五、数据分组


分组是指将数据分到不同的组,使每组中的元素拥有公共的属性。


5.1 GroupBy

对共享通用属性的元素进行分组,每组由一个IGrouping<TKey,TElement>对象表示

查询表达式语法

groupby


List<Product> products = new List<Product>
{
       new Product { Name = "Cola", CategoryId = 0 },
       new Product { Name = "Tea", CategoryId = 0 },
       new Product { Name = "Apple", CategoryId = 1 },
       new Product { Name = "Kiwi", CategoryId = 1 },
       new Product { Name = "Carrot", CategoryId = 2 } 
};
List<Category> categories = new List<Category> {
     new Category { Id = 0, CategoryName = "Beverage" },
     new Category { Id = 1, CategoryName = "Fruit" },
     new Category { Id = 2, CategoryName = "Vegetable" }
};
var proGroups = products.GroupBy(e => e.CategoryId);
foreach (var gp in proGroups)
{
     Console.WriteLine($"GroupByValue:{gp.Key}");
     foreach (var g in gp)
     {
         Console.WriteLine($"GroupValue:{g.Name}");
     }
}
Console.WriteLine($"=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=");
var goups = from product in products group product by product.CategoryId into productGroup select productGroup;
foreach (var ps in goups) 
{
   Console.WriteLine($"GroupByKey:{ps.Key}");
   foreach (var grp in ps) 
   {
       Console.WriteLine($"GroupValue:{grp.Name}");
   }
}


5.2 ToLookup

根据指定的键选择器和元素选择器函数,从IEnumerable生成一个泛型Lookup<TKey,TElement>。

语法:

public static System.Linq.ILookup<TKey,TElement> ToLookup<TSource,TKey,TElement> (this System.Collections.Generic.IEnumerable<TSource> source, Func<TSource,TKey> keySelector, Func<TSource,TElement> elementSelector);

类型参数

TSource source的元素类型。

TKey keySelector返回的键的类型。

TElement elementSelector返回的值的类型。

ILookup<int, string> lookupProduct = products .ToLookup(p => p.CategoryId,p => p.Name);
foreach (var vproduct in lookupProduct) 
{
     Console.WriteLine($"Key:{vproduct.Key}");
     foreach (var pro in vproduct) 
     {
          Console.WriteLine($"Value:{pro}");
      }
}


六、总结


LINQ采用表达式声明性的查询语法编写,这样可以用最少的代码进行对数据结构操作。Linq也提供丰富的操作函数,在实际的使用中根据不同应用常见选择恰当的方法。

目录
相关文章
|
19天前
|
数据可视化 网络协议 C#
C#/.NET/.NET Core优秀项目和框架2024年3月简报
公众号每月定期推广和分享的C#/.NET/.NET Core优秀项目和框架(每周至少会推荐两个优秀的项目和框架当然节假日除外),公众号推文中有项目和框架的介绍、功能特点、使用方式以及部分功能截图等(打不开或者打开GitHub很慢的同学可以优先查看公众号推文,文末一定会附带项目和框架源码地址)。注意:排名不分先后,都是十分优秀的开源项目和框架,每周定期更新分享(欢迎关注公众号:追逐时光者,第一时间获取每周精选分享资讯🔔)。
|
1月前
|
开发框架 JavaScript .NET
asp.net中条件查询+分页
asp.net中条件查询+分页
16 1
|
1月前
|
SQL 数据库 C#
C# .NET面试系列十一:数据库SQL查询(附建表语句)
#### 第1题 用一条 SQL 语句 查询出每门课都大于80 分的学生姓名 建表语句: ```sql create table tableA ( name varchar(10), kecheng varchar(10), fenshu int(11) ) DEFAULT CHARSET = 'utf8'; ``` 插入数据 ```sql insert into tableA values ('张三', '语文', 81); insert into tableA values ('张三', '数学', 75); insert into tableA values ('李四',
67 2
C# .NET面试系列十一:数据库SQL查询(附建表语句)
|
3月前
|
开发框架 前端开发 JavaScript
盘点72个ASP.NET Core源码Net爱好者不容错过
盘点72个ASP.NET Core源码Net爱好者不容错过
72 0
|
3月前
|
开发框架 .NET
ASP.NET Core NET7 增加session的方法
ASP.NET Core NET7 增加session的方法
37 0
|
3月前
|
开发框架 JavaScript .NET
ASP.NET Core的超级大BUG
ASP.NET Core的超级大BUG
43 0
|
1月前
|
SQL 数据库
使用ADO.NET查询和操作数据
使用ADO.NET查询和操作数据
10 0
|
1月前
|
开发框架 人工智能 .NET
C#/.NET/.NET Core拾遗补漏合集(持续更新)
C#/.NET/.NET Core拾遗补漏合集(持续更新)
|
1月前
|
开发框架 中间件 .NET
C# .NET面试系列七:ASP.NET Core
## 第一部分:ASP.NET Core #### 1. 如何在 controller 中注入 service? 在.NET中,在ASP.NET Core应用程序中的Controller中注入服务通常使用<u>依赖注入(Dependency Injection)</u>来实现。以下是一些步骤,说明如何在Controller中注入服务: 1、创建服务 首先,确保你已经在应用程序中注册了服务。这通常在Startup.cs文件的ConfigureServices方法中完成。例如: ```c# services.AddScoped<IMyService, MyService>(); //
65 0
|
1月前
|
开发框架 安全 .NET
C# .NET面试系列三:集合、异常、泛型、LINQ、委托、EF!
<h2>集合、异常、泛型、LINQ、委托、EF! #### 1. IList 接口与 List 的区别是什么? IList 接口和 List 类是C#中集合的两个相关但不同的概念。下面是它们的主要区别: <b>IList 接口</b> IList 接口是C#中定义的一个泛型接口,位于 System.Collections 命名空间。它派生自 ICollection 接口,定义了一个可以通过索引访问的有序集合。 ```c# IList 接口包含一系列索引化的属性和方法,允许按索引访问、插入、移除元素等。 由于是接口,它只定义了成员的契约,而不提供具体的实现。类似于 IEnumera
158 2