提供一组 static(在 Visual Basic 中为 Shared)方法,用于查询实现 IEnumerable < T > 的对象。但对于实现 IEnumerable < T > 的对象,这些方法大多可以以实例方法出现,而不一定使用 IEnumerable < T > 的静态方法;反之,不实现 IEnumerable < T > 接口的实例,这些方法不存在。 public static class Enumerable
继承
| Object | Enumerable |
|---|
备注
此类中的方法提供了标准查询运算符的实现,用于查询实现了 IEnumerable < T > 的数据源。标准查询运算符是遵循 LINQ 模式的通用方法,使您能够在任何基于 .NET 的编程语言中对数据执行遍历、筛选和投影操作。
此类中的大多数方法都定义为扩展方法,用于扩展 IEnumerable < T >。这意味着它们可以像实例方法一样在任何实现了 IEnumerable < T > 的对象上调用。
在返回值 可枚举对象 的查询中使用的方法,在枚举查询对象之前不会消耗目标数据。这称为延迟执行。在返回单个值的查询中使用的方法会立即执行并消耗目标数据。
方法
Aggregate
对 可枚举对象 应用 聚合器 函数。指定的 种子 值用作初始 聚合器 值(可以不指定),指定的 函数 用于处理结果值,并可选择使用 结果选择器 转换最终返回值。
public static T源 Aggregate < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , T源 , T源 > 函数 );
public static T聚合 Aggregate < T源 , T聚合 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , T聚合 种子 , Func < T聚合 , T源 , T聚合 > 函数 );
public static T结果 Aggregate < T源 , T聚合 , T结果 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , T聚合 种子 , Func < T聚合 , T源 , T聚合 > 函数 , Func < T聚合 , T结果 > 结果选择器 );参数
| 参数 | 类型 | 注解 |
|---|---|---|
| 源 | T源 | 源 的元素类型(可枚举类型) |
| 种子 | T聚合 | 初始 聚合器(T聚合)值,不指定则为 队列 的第一个元素 |
| 函数 | Func < T源 , T源 , T源 > Func < T聚合 , T源 , T聚合 > | 要在每个元素(可以抛弃第一个元素,未指定 种子 的话)上调用的 聚合器 函数 |
| 结果选择器 | Func < T聚合 , T结果 > | 将最终 聚合器 值转换为结果值的函数 |
返回值
| 类型 | 注解 |
|---|---|
| T结果 | 最终或转换后的聚合器值 |
异常
| 异常 | 注解 |
|---|---|
| ArgumentNullException | 源 或 函数 或 结果选择器 是 null |
| InvalidOperationException | 未指定 种子 时,源 是 Empty |
示例
以下示例展示了 Aggregate 没有种子的重载(反转一个 string 单集):
List < string > DJZfcs = [ "我" , "你" , "她" , "他" , "它" , "祂" ];
string Zfcs = DJZfcs . Aggregate ( static ( Z , xyg ) => $"{xyg} {Z}" );
Console . WriteLine ( Zfcs );以下示例展示了统计 int 单集中偶数个数的 Aggregate(初始化种子为 0):
List < int > DJZhss = [ 2 , 6 , 3 , 3 , 6 , 9 ];
int Zhss = DJZhss . Aggregate ( 0 , ( Zong , xyg ) => xyg % 2 == 0 ? Zong + 1 : Zong );
Console . WriteLine ( Zhss );以下示例展示了当 string 单集中的某个名字 xm 的 Length 最长时,输出该名字的大写形式(结果选择器):
List < string > XingMings = [ "Rose" , "SuXiaoDan" , "HuangYi" , "XiaHouLiangLiang" , "ZhouYing" , "OuYangMeiDangShang" ];
string XM长 = XingMings . Aggregate ( String . Empty , ( CDC , xyg ) => xyg . Length > CDC . Length ? xyg : CDC , xm => xm . ToUpper ( ) );
Console . WriteLine ( XM长 );备注
Aggregate 方法简化了对一 队列 值的计算操作。该方法的工作原理是:对 源 中除第一个元素外的每个元素调用一次 函数。每次调用 函数 时,Aggregate 都会将 队列 中的元素和一个聚合值(作为传给 函数 的第一个参数)一并传入。源 的第一个元素用作初始聚合值。函数 的结果会替换之前的聚合值。Aggregate 返回 函数 的最终结果。
Aggregate 方法的此重载并不适用于所有情况,因为它将 源 的第一个元素用作初始聚合值。如果返回值应仅包含 源 中满足特定条件的元素,您应该选择另一个重载。例如,如果您想计算 源 中偶数的总和,此重载并不可靠。如果第一个元素是奇数而非偶数,结果将不正确。
Aggregate 方法使对一 队列 值执行计算变得简单。此方法的工作原理是对 源 中的每个元素调用一次 函数。每次调用 函数 时,Aggregate 都会传递 队列 中的元素和一个聚合值(作为 函数 的第一个参数)。种子 参数的值用作初始聚合值。函数 的结果会替换之前的聚合值。Aggregate 返回 函数 的最终结果。
Aggregate 方法使对一 队列 值执行计算变得简单。此方法的工作方式是对 源 中的每个元素调用一次 函数。每次调用 函数 时,Aggregate 都会传递 队列 中的元素和一个聚合值(作为 函数 的第一个参数)。种子 参数的值用作初始聚合值。函数 的结果会替换之前的聚合值。函数 的最终结果会传递给 结果选择器,以获得 Aggregate 的最终结果。
为了简化常见的聚合操作,标准查询运算符还包括一个通用的计数方法 Count,以及四个数值聚合方法,即 Min、Max、Sum 和 Average。
AggregateBy
对 可枚举对象 应用聚合器函数,按键对结果进行分组。
public static System . Collections . Generic . IEnumerable < System . Collections . Generic . KeyValuePair < T键 , T聚合 > > AggregateBy < T源 , T键 , T聚合 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , T键 > 键选择器 , T聚合 种子 , Func < T聚合 , T源 , T聚合 > 函数 , System . Collections . Generic . IEqualityComparer < T键 >? 键比较器 = default );
public static System . Collections . Generic . IEnumerable < System . Collections . Generic . KeyValuePair < T键 , T聚合 > > AggregateBy < T源 , T键 , T聚合 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , T键 > 键选择器 , Func < T键 , T聚合 > 种子选择器 , Func < T聚合 , T源 , T聚合 > 函数 , System . Collections . Generic . IEqualityComparer < T键 >? 键比较器 = default );参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T源 | T | 源 的元素类型 |
| T键 | T | 键 的元素类型 |
| T聚合 | T | 聚合器 的元素类型 |
| 键选择器 | Func < T源 , T键 > | 一个用于提取每个元素的键的函数 |
| 种子 | T聚合 | 初始累加器值 |
| 种子选择器 | Func < T键 , T聚合 > | 用于生成初始累加器值的函数 |
| 函数 | Func < T聚合 , T源 , T聚合 > | 一个将在每个元素上调用的累加器函数 |
| 键比较器 | IEqualityComparer < T键 >? | 用于比较键的 IEqualityComparer < T > |
示例
以下示例展示了将一组整数分成三组(按照是否整除于 3 及其余数)并统计数量:
List<int> DJZhss = [ 2 , 10 , 6 , 10 , 3 , 3 , 6 , 9 , 4 , 7 , 7 ];
// 分组聚合:整除于 3 一组、整除于 3 余 1 一组,其余(整除于 3 余 2)一组
var JieGuo = DJZhss . AggregateBy (
keySelector: x => x % 3, // 分组规则:按整除于 3 的余数分
seed: 0, // 每组的聚合器种子
func: (zong, xyg) => zong + 1 // 每组的聚合逻辑
);
foreach ( var jg in JieGuo )
{
Console.WriteLine( $"{ ( jg . Key == 0 ? "整除于 3:" : jg . Key == 1 ? "整除于 3 余 1:" : "整除于 3 余 2:" ) } → {jg . Value} 个" );
}使用第二个重载(指定种子选择器):
List<int> DJZhss = [ 2 , 10 , 6 , 10 , 3 , 3 , 6 , 9 , 4 , 7 , 7 , 11 ];
// 分组聚合:整除于 3 一组、整除于 3 余 1一组,其余(整除于 3 余 2)一组
var JieGuo = DJZhss.AggregateBy (
keySelector: x => x % 3, // 分组规则:按整除于 3 的余数分
seedSelector: YuShu => YuShu switch // 每组的聚合器种子
{
0 => 100, // 整除以 100 为基数
1 => 200, // 余 1 以 200 为基数
2 => 300, // 余 2 以 300 为基数
_ => 0 // 无效以 0 为基数
},
func: (zong, xyg) => zong + 1 // 每组的聚合逻辑
);
foreach ( var jg in JieGuo )
{
Console.WriteLine( $"{ ( jg . Key == 0 ? "整除于 3:" : jg . Key == 1 ? "整除于 3 余 1:" : "整除于 3 余 2:" ) } → {jg . Value} 个" );
}备注
此方法类似于 GroupBy < T源 , T键 > ( IEnumerable < T源 > , Func < T源 , T键 > ) 方法,不同之处在于每个分组都被聚合为单个值,而不是为每个组分配一个集合。
All
确定 队列 中的所有元素是否都满足某个条件。 public static bool All < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , bool > 条件委托 );
参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T源 | T | 源 的元素类型 |
| 源 | T源 | 可枚举的 源 |
| 条件委托 | Func < T源 , bool > | 一个用于测试每个元素是否满足某个条件的函数 |
返回值
| 类型 | 注解 |
|---|---|
| bool | 如果 源 的每个元素都通过指定 条件委托 中的测试,或者该序列为空,则为 true;否则为 false |
异常
| 异常 | 注解 |
|---|---|
| ArgumentNullException | 源 或 条件委托 为 null |
示例
以下示例展示了如何使用 条件委托 决定 All 的 返回值(是否是正数、负数或偶数),并展示了它们的简写形式(可能很难理解):
List<int> DJZhss = [ 2 , 10 , 6 , 10 , 3 , 3 , 6 , 9 , 4 , 7 , 7 , 11 ];
Console . WriteLine ( DJZhss . All ( FF正数 ) ); // DJZhss . All ( x => x > 0 )
Console . WriteLine ( DJZhss . All ( FF负数 ) ); // DJZhss . All ( x => x < 0 )
Console . WriteLine ( DJZhss . All ( FF偶数 ) ); // DJZhss . All ( x => x % 2 == 0 )
static bool FF正数 ( int 整数 ) // => 整数 > 0;
{
if ( 整数 <=0 ) return false;
return true;
}
static bool FF负数 ( int 整数 ) // => 整数 < 0;
{
if ( 整数 >= 0 ) return false;
return true;
}
static bool FF偶数 ( int 整数 ) // => 整数 % 2 == 0;
{
if ( 整数 % 2 != 0 ) return false;
return true;
}备注
注意:此方法不会返回 队列 中的所有元素。相反,它会判断 队列 中的所有元素是否都满足某个条件。
一旦可以确定结果,源 的枚举就会停止。
在 Visual Basic 查询表达式语法中,Aggregate Into All ( ) 子句会转换为对 All 的调用。
Any
确定 队列 中是否存在元素(即 Count ≠ 0)或是否有元素(仅一个即可)满足条件。
public static bool Any < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 );
public static bool Any < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , bool > 条件委托 );参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T源 | T | 源 的元素类型 |
| 源 | T源 | 欲操作的 源 队列 |
| 条件委托 | Func < T源 , bool > | 欲对测试每个元素的 条件 函数 |
返回值
| 类型 | 注解 |
|---|---|
| bool | 若 源 不为 Empty 且至少有一个符合 条件委托,则为 true;否则为 false |
异常
| 异常 | 注解 |
|---|---|
| ArgumentNullException | 源 或 条件委托 为 null |
示例
以下示例展示了 Any 与 All 的区别(即全部符合条件和部分符合条件,哪怕是唯一一个的区别):
List<int> DJZhss = [ 2 , 10 , 6 , 10 , 3 , 3 , 6 , 9 , 4 , 7 , 7 , 11 ];
Console . WriteLine ( DJZhss . Any ( FF正数 ) ); // DJZhss . Any ( x => x > 0 )
Console . WriteLine ( DJZhss . Any ( FF负数 ) ); // DJZhss . Any ( x => x < 0 )
Console . WriteLine ( DJZhss . Any ( FF偶数 ) ); // DJZhss . Any ( x => x % 2 == 0 )
static bool FF正数 ( int 整数 ) // => 整数 > 0;
{
if ( 整数 <=0 ) return false;
return true;
}
static bool FF负数 ( int 整数 ) // => 整数 < 0;
{
if ( 整数 >= 0 ) return false;
return true;
}
static bool FF偶数 ( int 整数 ) // => 整数 % 2 == 0;
{
if ( 整数 % 2 != 0 ) return false;
return true;
}备注
注意:此方法不返回 队列 中的任何一个元素。相反,它会判断 队列 中是否有任何元素满足某个条件。
一旦可以确定结果,源 的枚举就会停止(Empty 队列会返回 false,因为没有一个元素符合条件)。
在 Visual Basic 查询表达式语法中,Aggregate Into Any ( ) 子句会转换为对 Any 的调用。
Append
将值追加到 队列 的末尾。实际并未修改 队列 的元素,而是返回(创建)一个包含指定元素的新的 队列。
` public static System . Collections . Generic . IEnumerable < T源 > Append < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , T源 追加元素 );
`
参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T源 | T | 源 的元素类型 |
| 源 | IEnumerable < T源 > | 一个队列 |
| 追加元素 | T源 | 欲追加的值 |
返回值
| 类型 | 注解 |
|---|---|
| IEnumerable < T源 > | 以 追加元素 结尾的队列 |
异常
| 异常 | 注解 |
|---|---|
| ArgumentNullException | 源 为 null |
示例
以下示例展示了如何向 队列 Append 一个值,以及并未修改源 队列:
List<int> DJZhss = [ 2 , 10 , 6 , 10 , 3 , 3 , 6 , 9 , 4 , 7 , 7 , 11 ];
// Append 并未修改原队列
DJZhss . Append ( 0 );
Console . WriteLine ( string . Join ( ',' , DJZhss ) );
// 应该将 Append 的返回值赋值给一个新的队列
HashSet < int > JHZhss = [ .. DJZhss . Append ( 0 ) ];
Console . WriteLine ( string . Join ( ',' , JHZhss ) );
IEnumerable < int > DLZhss = DJZhss . Append ( 0 ) ;
Console . WriteLine ( string . Join ( ',' , DLZhss ) );AsEnumerable
将输入作为 IEnumerable < T >(队列影像)类型返回。 public static System . Collections . Generic . IEnumerable < T源 > AsEnumerable < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 );
参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T源 | T | 源 的元素类型 |
| 源 | IEnumerable < T源 > | 欲转换为 IEnumerable < T源 >(影像)的队列 |
返回值
| 类型 | 注解 |
|---|---|
| IEnumerable < T源 > | 由 源 队列产生的影像 |
示例
以下示例展示了转换为 队列 的方式,并展示可以通过修改源队列同步修改其 AsEnumerable 版本:
List<int> DJZhss = [ 2 , 10 , 6 , 10 , 3 , 3 , 6 , 9 , 4 , 7 , 7 , 11 ];
IEnumerable < int > DLZhss = DJZhss . AsEnumerable ( );
FF显示队列 ( $"IEnumerable < int > DLZhss = DJZhss . AsEnumerable ( );" , DLZhss ); // 输出源队列(其实是影像)
DJZhss . Add ( 15 ); // 源队列 List 可以 Add(影像不能)
FF显示队列 ( $"DJZhss . Add ( 15 );" , DLZhss ); // 影像反映了原队列的改变
static void FF显示队列 ( string 说明 , IEnumerable < int > 队列 )
{
Console . WriteLine ( 说明 );
Console . WriteLine ( string . Join ( ',' , 队列 ) );
}备注
AsEnumerable 方法除了将 源 的编译时类型从实现 IEnumerable < T > 接口的类型更改为 IEnumerable < T > 类型本身外,没有其他作用。
AsEnumerable 可用于在序列实现 IEnumerable < T > 但同时拥有一组不同的公共查询方法时,在查询实现之间进行选择。例如,假设有一个泛型类 Table,它实现了 IEnumerable < T >,并且有自己的方法,如 Where、Select 和 SelectMany,对 Where 的调用会调用 Table 的 public Where 方法。表示数据库表的 Table 类型可以有一个 Where 方法,该方法将谓词参数作为表达式树,并将该树转换为 SQL 以进行远程执行。如果不希望进行远程执行(例如谓词调用了本地方法),则可以使用 AsEnumerable 方法来隐藏自定义方法,转而使用标准查询运算符。
Average
计算一个 队列 的平均值(仅限于数值类型)。
重载
| 重载 | 注解 |
|---|---|
| Average ( IEnumerable < 源类型 > ) | 计算队列的平均值(目标类型) |
| Average ( IEnumerable < Nullable < 源类型 > > ) | 计算(元素可 null)队列的平均值(目标类型) |
| Average < T源 > ( IEnumerable < T源 > , Func < T源 , 转换类型 > ) | 计算队列的平均值(目标类型) |
| Average < T源 > ( IEnumerable < T源 > , Func < T源 , < Nullable < 转换类型 > > ) | 计算队列的平均值(目标类型) |
public static float Average ( this IEnumerable < float > 源 );
public static float? Average ( this IEnumerable < float? > 源 );
public static decimal Average ( this IEnumerable < decimal > 源 );
public static decimal? Average ( this IEnumerable < decimal? > 源 );
public static double Average ( this IEnumerable < double > 源 );
public static double? Average ( this IEnumerable < double? > 源 );
public static double Average ( this IEnumerable < int > 源 );
public static double? Average ( this IEnumerable < int? > 源 );
public static double Average ( this IEnumerable < long > 源 );
public static double? Average ( this IEnumerable < long? > 源 );
public static float Average < T源 > ( this IEnumerable < T源 > 源 , Func < T源 , float > 元素选择器 );
public static float? Average < T源 > ( this IEnumerable < T源 > 源 , Func < T源 , float? > 元素选择器 );
public static decimal Average < T源 > ( this IEnumerable < T源 > 源 , Func < T源 , decimal > 元素选择器 );
public static decimal? Average < T源 > ( this IEnumerable < T源 > 源 , Func < T源 , decimal? > 元素选择器 );
public static double Average < T源 > ( this IEnumerable < T源 > 源 , Func < T源 , double > 元素选择器 );
public static double? Average < T源 > ( this IEnumerable < T源 > 源 , Func < T源 , int? > 元素选择器 );
public static double? Average < T源 > ( this IEnumerable < T源 > 源 , Func < T源 , long? > 元素选择器 );
public static double? Average < T源 > ( this IEnumerable < T源 > 源 , Func < T源 , double? > 元素选择器 );参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T源 | T | 源队列的元素类型 |
| 源 | T源 | 欲求平均值的队列 |
| 元素选择器 | Func < T源 , 数值类型 > | 对于元素的转换或条件计算的函数 |
返回值
| 参数类型或元素选择器返回类型 | 类型 | 注解 |
|---|---|---|
| 任意整型数 | double | 任意整型数 的元素平均值 |
| double | double | double 的元素平均值 |
| float | float | float 的元素平均值 |
| decimal | decimal | decimal 的元素平均值 |
| 任意整型数? | double? | 任意整型数 的元素平均值(可能为 null) |
| double? | double? | double 的元素平均值(可能为 null) |
| float? | float? | float 的元素平均值(可能为 null) |
| decimal? | decimal? | decimal 的元素平均值(可能为 null) |
异常
| 异常 | 注解 |
|---|---|
| ArgumentNullException | 源 是 null |
| InvalidOperationException | 源 为 Empty(仅当指定返回值不能为 null) |
| OverflowException | 总和 超出 Int64 . MaxValue 或 Decimal . MaxValue |
示例
以下示例使用了 Average 求得 int List 和 double List 的平均值:
List < int > DJZhss = [ 2 , 10 , 6 , 10 , 3 , 3 , 6 , 9 , 4 , 7 , 7 , 11 ];
double pjsZhss = DJZhss . Average ( );
Console . WriteLine ( pjsZhss );
List < double > DJSjds = [ 2.7 , 3.6 , 4.5 , 9.4 , 1.9 ];
double pjsSjds = DJSjds . Average ( );
Console . WriteLine ( pjsSjds );以下示例展示了如何使用元素选择器仅求部分元素的比例:
List < double > DJSjds = [ 2.7 , 3.6 , 4.5 , 9.4 , 1.9 ];
double pjsSjds = DJSjds . Average ( x => x + 2.0 >= 4.7 ? 1 : 0 );
Console . WriteLine ( pjsSjds );备注
在 Visual Basic 查询表达式语法中,Aggregate Into Average ( ) 子句会转换为对 Average 的调用。
当 返回值 为 float 或 double,且总和不在 float 或 double 的上下限(MaxValue 或 MinValue)之内时,该方法只会返回 ±∞。
Chunk
将队列的元素拆分为大小至多为 块长 的块。 public static System . Collections . Generic . IEnumerable < T源 [ ] > Chunk < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , int 块长 );
参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T源 | T | 源队列 的元素类型 |
| 源 | IEnumerable < T源 > | 欲分块的 源队列 |
| 块长 | int | 每个 块 的最大大小 |
返回值
| 类型 | 注解 |
|---|---|
| IEnumerable < T源 [ ] > | 一个 IEnumerable < T源 > 数组,每一个均包含 源队列 中的分块后的元素 |
异常
| 异常 | 注解 |
|---|---|
| ArgumentOutOfRangeException | 块长 小于 1 |
| ArgumentNullException | 源 是 null |
示例
以下示例将一个 int 队列分隔为最大可能为 3 个元素的块:
List < int > DLZhss = [ 7 , 8 , 1 , 5 , 16 , 11 , 13 ];
IEnumerable < int [ ] > FK = DLZhss . Chunk ( 3 );
int z = 0;
foreach ( int [ ] fK in FK )
{
z++;
FF显示队列 ( $"分块 {z}:" , fK );
}
static void FF显示队列 ( string 说明 , IEnumerable < int > 队列 )
{
Console . WriteLine ( 说明 );
Console . WriteLine ( string . Join ( ',' , 队列 ) );
}备注
块数 = 源队列 . Count 整除 块长 + ( 余数 > 0 ? 1 : 0 )
唯一的一块(块长 小于 队列 . Count)或最后一块的 Count 可能小于 块长。
Concat
连接两个 队列。 public static System . Collections . Generic . IEnumerable < T源 > Concat < T源 > (this System . Collections . Generic . IEnumerable < T源 > 首 , System . Collections . Generic . IEnumerable < T源 > 次 );
参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T源 | T | 首、次 以及 结果队列的元素类型 |
| 首 次 | IEnumerable < T源 > | 欲连接的两个队列 |
返回值
| 类型 | 注解 |
|---|---|
| IEnumerable < T源 > | 按顺序连接的两个队列 |
异常
| 异常 | 注解 |
|---|---|
| ArgumentNullException | 首 和/或 次 是 null |
示例
以下示例展示了 Concat 连接两个 int 队列(首 是 List,次 是 SortedSet):
List < int > DLZhss = [ 7 , 8 , 1 , 5 , 16 , 11 , 13 ];
SortedSet < int > YouXuJiHeZhss = [ 3 , 1 , 6 , 5 ];
IEnumerable < int > LianJie = Enumerable . Concat ( DLZhss , YouXuJiHeZhss );
FF显示队列 ( "连接后:" , LianJie );
DLZhss . Add ( 24 );
FF显示队列 ( "连接(添加 24)后:" , LianJie );
static void FF显示队列 ( string 说明 , IEnumerable < int > 队列 )
{
Console . WriteLine ( 说明 );
Console . WriteLine ( string . Join ( ',' , 队列 ) );
}连接两个序列的另一种方法是构建一个序列集合(例如数组),然后应用 SelectMany 方法,并向其传递恒等选择器函数。下面的示例演示了 SelectMany 的这种用法:
List < int > DLZhss = [ 7 , 8 , 1 , 5 , 16 , 11 , 13 ];
SortedSet < int > YouXuJiHeZhss = [ 3 , 1 , 6 , 5 ];
IEnumerable < int > LianJie = new IEnumerable < int > [ ] { DLZhss , YouXuJiHeZhss } . SelectMany ( x => x );
FF显示队列 ( "连接结果:" , LianJie );
DLZhss . Add ( 24 );
FF显示队列 ( "连接结果(添加 24 之后):" , LianJie );
static void FF显示队列 ( string 说明 , IEnumerable < int > 队列 )
{
Console . WriteLine ( 说明 );
Console . WriteLine ( string . Join ( ',' , 队列 ) );
}备注
此方法通过使用延迟执行来实现。即时返回值是一个对象,该对象存储执行此操作所需的所有信息。此方法所表示的查询在枚举该对象之前不会执行,枚举可以通过直接调用其 GetEnumerator 方法,或在 C# 中使用 foreach,或在 Visual Basic 中使用 For Each 来完成。
Concat 返回值实际是个影像,对源队列(首 和 次)的任何改变都会反映在 Concat 返回值中。
Concat 方法与 Union 方法的不同之处在于,Concat 方法返回输入序列中的所有原始元素。Union 方法仅返回唯一元素(去重)。
Contains
确定队列是否包含指定元素。
重载
| 重载 | 注解 |
|---|---|
| Contains < T源 > ( IEnumerable < T源 > , T源 ) | 确定元素时使用默认的相等比较器 |
| Contains < T源 > ( IEnumerable < T源 > , T源 , IEqualityComparer < T源 > ) | 确定元素时使用指定的相等比较器 |
public static bool Contains < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , T源 值 );
public static bool Contains < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , T源 值 , System . Collections . Generic . IEqualityComparer < T源 >? 比较器 );参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T源 | T | 源 的数据类型 |
| 源 | IEnumerable < T源 > | 欲确定是否存在元素的队列 |
| 值 | T源 | 欲确定队列中是否存在的元素 |
| 比较器 | IEqualityComparer < T源 >? | 确定元素是否存在的比较器,null 则为默认比较器 |
返回值
| 类型 | 注解 |
|---|---|
| bool | 如果 源 中存在 值(按比较器),则为 true;否则为 false |
异常
| 异常 | 注解 |
|---|---|
| ArgumentNullException | 源 为 null |
示例
以下示例展示了默认的比较器的 Contains:
List < string > DJ水果在冰箱里 = [ "苹果" , "梨" , "芒果" , "香蕉" ];
bool ber有葡萄吗 = DJ水果在冰箱里 . Contains ( "葡萄" );
bool ber有梨吗 = DJ水果在冰箱里 . Contains ( "梨" );
Console . WriteLine ( $"有葡萄吗?{( ber有葡萄吗 ? "有" : "没有" )}" );
Console . WriteLine ( $"有梨吗?{( ber有梨吗 ? "有" : "没有" )}" );以下示例展示如何定义一个 比较器,比较仓库里的食材是否存在相同规格(食材名和食材量均相同,例如一包 6.25 公斤的大蒜),由于容错性,允许上下浮动 5%:
List < LEI食材 > SHCs =
[
new LEI食材 ( "土豆" , 17.5 ),
new LEI食材 ( "大蒜" , 6.25 ),
new LEI食材 ( "菠菜" , 12 ),
];
LEI食材比较器 bjq = new ( );
LEI食材 DaSuan = new ( "大蒜" , 6.28 );
LEI食材 BoCai = new ( "菠菜" , 10 );
bool ber大蒜 = SHCs . Contains ( DaSuan , bjq );
bool ber菠菜 = SHCs . Contains ( BoCai , bjq );
Console . WriteLine ( ber大蒜 ? $"仓库里有 {DaSuan . 食材量} 的{DaSuan . 食材名}" : $"仓库里没有{DaSuan . 食材名},或{DaSuan . 食材名}不是 {DaSuan . 食材量}" );
Console . WriteLine ( ber菠菜 ? $"仓库里有 {BoCai . 食材量} 的{BoCai . 食材名}" : $"仓库里没有{BoCai . 食材名},或{BoCai . 食材名}不是 {BoCai . 食材量}" );
public class LEI食材 ( string 名称 , double 数量 )
{
// 食材名称
public string 食材名
{
get
{ return 名称; }
set
{ 名称 = value; }
}
// 食材量(kg)
public double 食材量
{
get
{ return 数量; }
set
{ 数量 = value; }
}
public event Action < string >? SHJ库存状态;
public bool FF是否需要补充 ( double 日需量 )
{
if ( 食材量 == 0 )
{
SHJ库存状态?.Invoke ( $"{食材名}:没有" );
return true;
}
if ( 食材量 <= 日需量 * 0.8 )
{
SHJ库存状态?.Invoke ( $"{食材名}:少于日常需要量的 80%" );
return true;
}
return false;
}
}
public class LEI食材比较器 : IEqualityComparer < LEI食材 >
{
public bool Equals ( LEI食材? x , LEI食材? y )
{
if ( x is null && y is null ) return true;
if ( x is null || y is null ) return false;
return x . 食材名 == y . 食材名 && Math . Abs ( x . 食材量 - y . 食材量 ) < ( x . 食材量 * 0.05 );
}
public int GetHashCode ( [DisallowNull] LEI食材 SHC )
{
return HashCode . Combine ( SHC . 食材名 , SHC . 食材量 );
}
}备注
如果 源 的类型实现了 ICollection < T >,则会调用该实现中的 Contains 方法来获取结果。否则,此方法将确定 源 是否包含指定的元素。
一旦找到匹配的元素,枚举就会终止。
通过使用默认的相等比较器 Default,或指定的 比较器 将元素与指定值进行比较。
Count 和 LongCount
返回队列中元素的数量。
重载
| 重载 | 注解 |
|---|---|
| Count < T源 > ( IEnumerable < T源 > ) | 返回队列中的元素数量 |
| Count < T源 > ( IEnumerable < T源 > , Func < T源 , Boolean > ) | 返回队列中的符合某个条件的元素数量 |
| LongCount < T源 > ( IEnumerable < T源 > ) | 返回队列中的元素数量 |
| LongCount < T源 > ( IEnumerable < T源 > , Func < T源 , Boolean > ) | 返回队列中的符合某个条件的元素数量 |
public static int Count < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源);
public static int Count < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , bool > 条件委托 );
public static long LongCount < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源);
public static long LongCount < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , bool > 条件委托 );参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T源 | T | 源 队列的元素类型 |
| 源 | IEnumerable < T源 > | 确定 Count 的 源队列 |
| 条件委托 | Func < T源 , bool > | 确定元素是否符合某个条件的函数 |
返回值
| 方法 | 类型 | 注解 |
|---|---|---|
| Count LongCount | int long | 源 的元素数量 |
异常
| 异常 | 注解 |
|---|---|
| ArgumentNullException | 源 或 条件委托 为 null |
| OverflowException | 源 的 Count 大于 int . MaxValue 源 的 LongCount 大于 long . MaxValue |
示例
以下示例创建一个随机的 int 队列,并使用 Count 方法返回其元素数量(也是随机的),并使用条件委托返回其大于零的元素数量:
List < int > DJZhss = [ ];
Random SJS = new ( );
int zhsCount = SJS . Next ( 0 , 100 );
for ( int z = 0 ; z < zhsCount ; z++ )
{
DJZhss . Add ( SJS . Next ( int . MinValue , int . MaxValue ) );
}
Console . WriteLine ( $"DJZhss . Count = {DJZhss . Count}" );
Console . WriteLine ( $"DJZhss . Count ( FF大于零 ) = {DJZhss . Count ( FF大于零 )}" );
static bool FF大于零 ( int 整数 )
{
if ( 整数 > 0 )
return true;
else
return false;
}备注
如果 源 的类型实现了 ICollection < T >,则使用该实现来获取元素计数。否则,此方法将确定计数。
当你期望并希望允许结果大于 int . MaxValue 时,应该使用 LongCount 方法。
在 Visual Basic 查询表达式语法中,Aggregate Into Count ( ) 子句会转换为对 Count 的调用。
CountBy
返回按键分组的源队列中的元素计数。 public static System . Collections . Generic . IEnumerable < System . Collections . Generic . KeyValuePair < T键 , int > > CountBy < T源 , T键 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , T键 > 键选择器 , System . Collections . Generic . IEqualityComparer < T键 >? 键比较器 = default );
参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T源 | T | 源 的元素类型 |
| T键 | T | 键选择器 的返回值类型 |
| 源 | IEnumerable < T源 > | 包含计数元素的队列 |
| 键选择器 | Func < T源 , T键 > | 提取每个元素的键的函数 |
| 键比较器 | IEqualityComparer < T键 >? | 比较键的 比较器,null 则为 default |
返回值
| 类型 | 注解 |
|---|---|
| IEnumerable < KeyValuePair < T键 , Int32 > > | 可枚举集合,包括 源 中的每个键出现的频率 |
示例
以下示例生成一个 100 个元素的 int List,并用 CountBy 统计零、正数、负数的频率:
List < int > DJZhss = [ ];
Random SJS = new ( );
for ( int z = 0 ; z < 100 ; z++ )
{
DJZhss . Add ( SJS . Next ( -20 , 20 ) );
}
IEnumerable < KeyValuePair < int , int > > ZF0频率 = DJZhss . CountBy ( FF正负零 );
foreach ( KeyValuePair < int , int > pl in ZF0频率 )
{
string zfcZF = pl . Key switch
{
> 0 => "正数",
< 0 => "负数",
0 => "零",
};
Console . WriteLine ( $"{zfcZF} → {pl . Value}" );
}
static int FF正负零 ( int 整数 ) => 整数 switch
{
> 0 => 1,
< 0 => -1,
0 => 0
};DefaultIfEmpty
返回队列的副本;如果序列为 Empty(不是 null),则返回包含默认值的单元素队列。
重载
| 重载 | 注解 |
|---|---|
| DefaultIfEmpty < T源 > ( IEnumerable < T源 > ) | 返回队列的副本;如果 源 为 empty,则返回包含一个 T源 的默认值的元素的队列 |
| DefaultIfEmpty < T源 > ( IEnumerable < T源 > , T源 ) | 返回队列的副本;如果队列为 Empty,则返回唯一元素(指定默认值)的队列 |
public static System . Collections . Generic . IEnumerable < T源? > DefaultIfEmpty < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 );
public static System . Collections . Generic . IEnumerable < T源 > DefaultIfEmpty < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , T源 默认值 );参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T源 | T | 源 和返回值队列的元素类型 |
| 源 | IEnumerable < T源 > | 欲返回的队列 |
| 默认值 | T源 | 当 源 为 Empty 时的返回队列的单元素的值 |
返回值
| 类型 | 注解 |
|---|---|
| IEnumerable < T源 > | 仅当 源 为 Empty,则返回单元素队列,其元素值为 源 类型的默认值或指定的 默认值;否则,是 源 的副本 |
示例
以下示例展示了 int List 的 DefaultIfEmpty 返回值(包括指定返回值):
List < int > DJZhss = [ ];
List < int > DJZhss1 = [ 2 ];
IEnumerable < int > DJ默认 = DJZhss . DefaultIfEmpty ( );
IEnumerable < int > DJ默认1 = DJZhss . DefaultIfEmpty ( 1 );
IEnumerable < int > DJ有元素 = DJZhss1 . DefaultIfEmpty ( );
Console . WriteLine ( "当队列为 Empty,返回单个具有 类参 默认值的元素的队列:" );
foreach ( int z in DJ默认 )
Console . WriteLine ( z );
Console . WriteLine ( "当队列为 Empty,返回单个具有指定 默认值 的元素的队列:" );
foreach ( int z in DJ默认1 )
Console . WriteLine ( z );
Console . WriteLine ( "当队列不为 Empty,返回队列本身:" );
foreach ( int z in DJ有元素 )
Console . WriteLine ( z );备注
此方法通过使用延迟执行来实现。即时返回值是一个对象,该对象存储执行此操作所需的所有信息。此方法所表示的查询在枚举该对象之前不会执行,枚举可以通过直接调用其 GetEnumerator 方法,或者在 C# 中使用 foreach,在 Visual Basic 中使用 For Each 来实现。
若不指定 默认值,引用类型和可空类型的默认值都是 null。输出 null 意义不大,应指定一个默认值(null 或 无 或类等的 ToString ( )),并确保其他输出不会是该字符串。
当此方法与 GroupJoin 方法结合使用时,可用于生成左外连接。
Distinct
自队列中移除重复的元素(保留第一个)。实际上返回值类似于 HashSet,但保持原队列的顺序。
重载
| 重载 | 注解 |
|---|---|
| Distinct < T源 > ( IEnumerable < T源 > ) | 使用默认的相等比较器,移除 队列 中重复的元素 |
| Distinct < T源 > ( IEnumerable < T源 > , IEqualityComparer < T源 > ) | 使用指定的相等比较器,移除 队列 中重复的元素 |
public static System . Collections . Generic . IEnumerable < T源 > Distinct < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 );
public static System . Collections . Generic . IEnumerable < T源 > Distinct < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , System . Collections . Generic . IEqualityComparer < T源 >? 比较器 );参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T源 | T | 源 和返回值的数据类型 |
| 源 | IEnumerable < T源 > | 欲移除重复元素的队列 |
| 比较器 | IEqualityComparer < T源 >? | 值的比较器,null 则为默认比较器 |
返回值
| 类型 | 注解 |
|---|---|
| IEnumerable < T源 > | 一个 源 中按比较器重复的元素被移除的队列 |
示例
以下示例在一个 int 队列中,移除重复数的 Distinct:
List < int > DJZhss = [ ];
Random SJS = new ( );
for ( int z = 0 ; z < 10 ; z++ )
{
DJZhss . Add ( SJS . Next ( 0 , 10 ) );
}
IEnumerable < int > Zhss = DJZhss . Distinct ( );
Console . WriteLine ( string . Join ( "," , DJZhss ) );
Console . WriteLine ( string . Join ( ",", Zhss ) );备注
此方法通过使用延迟执行来实现。即时返回值是一个对象,该对象存储执行此操作所需的所有信息。此方法所表示的查询在枚举该对象之前不会执行,枚举可以通过直接调用其 GetEnumerator 方法,或者在 C# 中使用 foreach,在 Visual Basic 中使用 For Each 来完成。
Distinct 方法返回一个不包含重复值的无序序列。它使用默认的相等比较器 Default 来比较值。指定比较器可以使比较元素有不同的比较方法。
在 Visual Basic 查询表达式语法中,Distinct 子句会转换为对 Distinct 的调用。
默认的相等比较器 Default 用于比较实现了 IEquatable < T > 泛型接口的类型的值。若要比较自定义数据类型,你需要实现此接口,并为该类型提供自己的 GetHashCode 和 Equals 方法。
DistinctBy
按照条件在队列中去掉重复元素(保留第一个)。
重载
| 重载 | 注解 |
|---|---|
| DistinctBy < T源 , T键 > ( IEnumerable < T源 > , Func < T源 , T键 > ) | 根据指定的键选择器函数从队列中去掉重复的元素 |
| DistinctBy < T源 , T键 > ( IEnumerable < T源 > , Func < T源 , T键 > , IEqualityComparer < T键 > ) | 根据指定的键选择器函数和比较器从队列中去掉重复的元素 |
public static System . Collections . Generic . IEnumerable < T源 > DistinctBy < T源 , T键 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , T键 > 键选择器 );
public static System . Collections . Generic . IEnumerable < T源 > DistinctBy < T源 , T键 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , T键 > 键选择器 , System . Collections . Generic . IEqualityComparer < T键 >? 比较器 );参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T源 | T | 源 的元素类型 |
| T键 | T | 区分元素的 键 的类型 |
| 源 | IEnumerable < T源 > | 欲移除重复元素的队列 |
| 键选择器 | Func < T源 , T键 > | 提取每个元素的键的函数 |
| 比较器 | IEqualityComparer < T键 >? | 键 的比较器,null 则为 default |
返回值
| 类型 | 注解 |
|---|---|
| IEnumerable < T源 > | 源 中按照规则去除重复元素的队列 |
异常
| 异常 | 注解 |
|---|---|
| ArgumentNullException | 源 为 null |
示例
以下示例描述了某段时间内小卖部来的顾客的情况(包括有什么人来,和买过 26.5 元的物品的),但去重了:
List < LEI顾客 > GuKe =
[
new LEI顾客 ( "Rose" , 26.5m ),
new LEI顾客 ( "Mike" , 18m ),
new LEI顾客 ( "Tom" , 26.5m ),
new LEI顾客 ( "Mike" , 26m )
];
IEnumerable < LEI顾客 > XM去重 = GuKe . DistinctBy ( g => g . 姓名 );
IEnumerable < LEI顾客 > JY去重 = GuKe . DistinctBy ( g => g . 交易 );
FF显示队列 ( "源队列:" , GuKe );
FF显示队列 ( "姓名去重:" , XM去重 );
FF显示队列 ( "交易额去重:" , JY去重 );
static void FF显示队列 ( string 说明 , IEnumerable < LEI顾客 > 队列 )
{
Console . WriteLine ( 说明 );
Console . WriteLine ( string . Join ( ',' , 队列 ) );
}
public class LEI顾客 ( string 姓名 , decimal 交易额 )
{
private string _xm = 姓名;
private decimal _jy = 交易额;
public string 姓名 { get { return _xm; } set { _xm = value; } }
public decimal 交易 { get { return _jy; } set { _jy = value; } }
public override string ToString ( )
{
return $"{_xm}\t{_jy}";
}
}以下示例展示了一个总店分别按照分店的是否有货(白酒、啤酒、黄酒和清酒)来输出的场景:
List < LEI售货员 > ygs =
[
new LEI售货员 ( "小静" , [ "啤酒" , "白酒"] ),
new LEI售货员 ( "晓宁" , [ "啤酒" , "清酒"] ),
];
IEnumerable < string > xiaojing = ygs [ 0 ] . 货品;
IEnumerable < string > xiaoning = ygs [ 1 ] . 货品;
IEnumerable < string > zong = xiaojing . Concat ( xiaoning ) . DistinctBy ( s => s );
Console . WriteLine ( $"有白酒吗?{( ( zong . Contains ( "白酒" ) ? "有" : "没有" ) )}" );
Console . WriteLine ( $"有黄酒吗?{( ( zong . Contains ( "黄酒" ) ? "有" : "没有" ) )}" );
public class LEI售货员 ( string 姓名 , string [ ] 货品 )
{
private string _xm = 姓名;
private string [ ] _hp = 货品;
public string 姓名 { get { return _xm; } set { _xm = value; } }
public string [ ] 货品 { get { return _hp; } set { _hp = value; } }
}备注
此方法通过使用延迟执行来实现。即时返回值是一个对象,该对象存储执行此操作所需的所有信息。此方法所表示的查询在枚举该对象之前不会执行,枚举可以通过直接调用其 GetEnumerator 方法,或者在 C# 中使用 foreach,在 Visual Basic 中使用 For Each 来完成。
当不需要知道队列中重复元素有多少,只需要知道有没有,此方法即可返回一个相对缩容的小队列,查询搜索效能比较高(相对于一些庞大的数据队列来说)。
DistinctBy 方法返回一个不包含重复值的无序序列。使用指定的比较器或默认的相等比较器 Default 用于比较值。
ElementAt 和 ElementAtOrDefault
返回索引或 int 指定索引处的元素值;仅当索引或 int 不存在于 源 的有效范围内,ElementAtOrDefault 返回 T 的默认值。
重载
| 重载 | 注解 |
|---|---|
| ElementAt < T源 > ( IEnumerable < T源 > , 索引 ) ElementAt < T源 > ( IEnumerable < T源 > , 整数 ) ElementAtOrDefault < T源 > ( IEnumerable < T源 > , 索引 ) ElementAtOrDefault < T源 > ( IEnumerable < T源 > , 整数 ) | 返回 索引 或 整数 指定位置的元素值 |
public static TSource ElementAt < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Index 索引 );
public static TSource ElementAt < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , int 整数 );
public static TSource ElementAtOrDefault < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Index 索引 );
public static TSource ElementAtOrDefault < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , int 整数 );参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T源 | T | 源 的元素类型和返回值的类型 |
| 源 | IEnumerable < T源 > | 欲返回元素值的队列 |
| 索引 | Index | 欲返回元素值的索引,可以是来自起始或末尾 |
| 整数 | int | 欲返回元素值的索引 |
返回值
| 类型 | 注解 |
|---|---|
| T源 | 指定索引位置处的元素值(ElementAtOrDefault 会在索引不在 队列 有效范围内返回默认值 |
异常
| 异常 | 注解 |
|---|---|
| ArgumentNullException | 源 为 null |
| ArgumentOutOfRangeException | 仅限于 ElementAt,即 索引 或 整数 不在 队列 有效范围内 |
示例
以下示例展示了两个方法对于某个索引或整数值是否存在于队列中的返回值:
List < int > DJZhss = [ 1 , 7 , 2 , 6 ];
try
{
Console . WriteLine ( DJZhss . ElementAt ( 2 ) );
}
catch ( Exception yc ) { Console . WriteLine ( yc . Message ); }
try
{
Console . WriteLine ( DJZhss . ElementAtOrDefault ( 2 ) );
}
catch ( Exception yc ) { Console . WriteLine ( yc . Message ); }
try
{
Console . WriteLine ( DJZhss . ElementAt ( 7 ) );
}
catch ( Exception yc ) { Console . WriteLine ( yc . Message ); }
try
{
Console . WriteLine ( DJZhss . ElementAtOrDefault ( 7 ) );
}
catch ( Exception yc ) { Console . WriteLine ( yc . Message ); }
Index sy = new( 1 );
try
{
Console . WriteLine ( DJZhss . ElementAt ( sy ) );
}
catch ( Exception yc ) { Console . WriteLine ( yc . Message ); }
try
{
Console . WriteLine ( DJZhss . ElementAtOrDefault ( sy ) );
}
catch ( Exception yc ) { Console . WriteLine ( yc . Message ); }备注
如果 源 的类型实现了 IList < T >,则会使用该实现来获取指定索引处的元素。否则,此方法会获取指定的元素。
如果 索引 或 整数 超出队列的有效范围,ElementAt 方法会抛出 ArgumentOutOfRangeException 异常。若要在指定索引超出范围时返回默认值,请使用 ElementAtOrDefault 方法。ElementAtOrDefault 的 源 的 T源 是引用或可空类型时默认值是 null。
Empty
生成一个与 源 队列元素类型相同的 Empty 队列(不是 null)。 public static System . Collections . Generic . IEnumerable < T源 > Empty < T源 > ( );
参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T源 | T | 返回值的元素类型 |
返回值
| 类型 | 注解 |
|---|---|
| IEnumerable < T源 > | 一个 T源 为元素类型的队列,但是为 Empty(不是 null,Count = 0) |
示例
以下示例生成了一个新的 Empty 队列: IEnumerable < int > Kong = Enumerable . Empty < int > ( );
备注
Empty 方法会缓存一个 T源 类型的空队列。当枚举它返回的对象时,不会生成任何元素。
在某些情况下,此方法对于向接受 IEnumerable < T > 的用户定义方法传递空队列很有用。它还可用于为 Union 等方法生成中性元素。
Except
生成两个队列的差集。其元素包括 被减数队列 中存在但 减数队列 中不存在的元素。
重载
| 重载 | 注解 |
|---|---|
| Except < T源 > ( IEnumerable < T源 > 被减数队列 , IEnumerable < T源 > 减数队列 ) | |
| 生成 被减数队列 和 减数队列 之间的 差集 | |
| Except < T源 > ( IEnumerable < T源 > 被减数队列 , IEnumerable < T源 > 减数队列 , IEqualityComparer < T源 >? 比较器 ) | 按照比较器的返回值,生成 被减数队列 和 减数队列 之间的 差集 |
public static System . Collections . Generic . IEnumerable < T源 > Except < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 被减数队列 , System . Collections . Generic . IEnumerable < T源 > 减数队列 );
public static System . Collections . Generic . IEnumerable < T源 > Except < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 被减数队列 , System . Collections . Generic . IEnumerable < T源 > 减数队列 , System . Collections . Generic . IEqualityComparer < T源 >? 比较器 );参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T源 | T | 被减数队列 和 减数队列 的元素类型 |
| 被减数队列 减数队列 | IEnumerable < T源 > | 欲求差值的和欲减去重复值的队列 |
| 比较器 | IEqualityComparer < T源 >? | 比较元素的比较器,null 则为 default |
返回值
| 类型 | 注解 |
|---|---|
| IEnumerable < T源 > | 在 被减数队列 中移除 减数队列 中共有的元素 的新的队列 |
异常
| 异常 | 注解 |
|---|---|
| ArgumentNullException | 被减数队列 或 减数队列 为 null |
示例
以下示例展示了如何生成一个差集:
string [ ] DJ被减数 = [ "1" , "7" , "2" , "6" , "2" , "15" ];
string [ ] DJ减数 = [ "1" , "7" , "8" , "10" , "11" , "12345" ];
IEnumerable < string > Cha = Enumerable . Except ( DJ被减数 , DJ减数 );
FF显示队列 ( "差队列:" , Cha );
static void FF显示队列 ( string 说明 , IEnumerable < string > 队列 )
{
Console . WriteLine ( 说明 );
Console . WriteLine ( string . Join ( ',' , 队列 ) );
}注解
此方法是使用延迟执行实现的。即时返回值是一个对象,用于存储执行操作所需的所有信息。除非通过直接调用其 GetEnumerator 方法或在 C# 中的 foreach 或在 Visual Basic 中的 For Each 来使用枚举对象,否则不会执行此方法表示的查询。
默认相等比较器 Default 用于比较类型的值。若要比较自定义数据类型,需要重写 Equals 和 GetHashCode 方法,并选择性地在自定义类型中实现 IEquatable < T > 泛型接口。
ExceptBy
重载
| 重载 | 注解 |
|---|---|
| ExceptBy < T被减 , T减 > ( IEnumerable < T被减 > , IEnumerable < T减 > , Func < T被减 , T减 > ) | 根据指定的键选择器函数生成两个序列的差集 |
| ExceptBy < T被减 , T减 > ( IEnumerable < T被减 > , IEnumerable < T减 > , Func < T被减 , T减 > , IEqualityComparer < T减 > ) | 根据指定的键选择器函数和比较器生成两个序列的差集 |
public static System . Collections . Generic . IEnumerable < T被减 > ExceptBy < T被减 , T减 > ( this System . Collections . Generic . IEnumerable < T被减 > 被减数队列 , System . Collections . Generic . IEnumerable < T减 > 减数队列 , Func < T被减 , T减 > 键选择器 );
public static System . Collections . Generic . IEnumerable < T被减 > ExceptBy < T被减 , T减 > ( this System . Collections . Generic . IEnumerable < T被减 > 被减数队列 , System . Collections . Generic . IEnumerable < T减 > 减数队列 , Func < T被减 , T减 > 键选择器 , IEqualityComparer < T减 > 键比较器 );参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T被减 T减 | T | 被减数队列 和 减数队列 的元素类型 |
| 被减数队列 减数队列 | IEnumerable < T被减 > IEnumerable < T减 > | 欲求差集的队列 |
| 键选择器 | Func < T被减 , T减 > | 用于提取每个元素的键的函数 |
| 键比较器 | IEqualityComparer < T减 > | 用于比较键值的比较器 |
返回值
| 类型 | 注解 |
|---|---|
| IEnumerable < T被减 > | 按照 键选择器 和可选的 键比较器 确定的差集(HashSet 底层,无重复);包括 被减数队列 中所有在 减数队列 中不存在的元素 |
示例
以下示例展示了两个 int 队列的差集,第一个差集使用了默认的键选择器(返回原值);第二个差集使用了仅限于正数的键选择器,第三个差集展示了如何求两个不同与元素类型的队列的差集:
IEnumerable < int > DJ被减数 = [ -1 , 7 , -2 , 6 , 2 , -15 ];
IEnumerable < int > DJ减数 = [ 1 , 7 , -8 , 10 , -11 , 12345 ];
IEnumerable < string > DJ减数ZFC = [ "-1" , "2" , "3" ];
IEnumerable < int > Cha默认 = DJ被减数 . ExceptBy ( DJ减数 , x => x ); // 默认的键选择器
IEnumerable < int > ChaZHS = Enumerable . ExceptBy < int , int > ( DJ被减数 , DJ减数 , FFZHS大于零 ); // 返回值是 int 的键选择器(大于零)
IEnumerable < int > ChaZFC = Enumerable . ExceptBy < int , string? > ( DJ被减数 , DJ减数ZFC , FFZFC大于零 ); // 返回值是 string 的键选择器(大于零)
FF显示队列 ( $"\n差集 {{{string . Join ( ',' , DJ被减数)}}} - {{{string . Join ( ',' , DJ减数 )}}}:\n" , Cha默认 );
FF显示队列 ( $"\n差集(仅限大于零的元素) {{{string . Join ( ',' , DJ被减数 )}}} - {{{string . Join ( ',' , DJ减数 )}}}:\n" , ChaZHS );
FF显示队列 ( $"\n差集(仅限大于零的元素,减数队列 是 string) {{{string . Join ( ',' , DJ被减数 )}}} - {{{string . Join ( ',' , DJ减数ZFC )}}}:\n" , ChaZFC );
// ExceptBy 的示例函数(确保返回值中只有大于零的元素,小于零的键值被改为减数队列中的 Max,或者任意减数元素,所以被排除在结果之外)
string? FFZFC大于零 ( int 元素 )
{
return 元素 > 0 ? 元素 . ToString ( ) : DJ减数ZFC . First ( );
}
int FFZHS大于零 ( int 元素 )
{
return 元素 > 0 ? 元素 : DJ减数 . First ( );
}
static void FF显示队列 ( string 说明 , IEnumerable < int > 队列 )
{
Console . WriteLine ( 说明 );
Console . WriteLine ( string . Join ( ',' , 队列 ) );
}First、FirstOrDefault、Last、LastOrDefault
First 和 Last 分别返回队列的第一个和最后一个(符合条件的)元素。队列不能是 null 或 Empty。
FirstOrDefault 和 LastOrDefault 分别返回队列的第一个和最后一个(符合条件的)元素。但当队列是 Empty 时,会返回队列元素类型的默认值。队列不能是 null。
重载
| 重载 | 注解 |
|---|---|
| First < T源 > ( IEnumerable < T源 > ) | 返回队列的第一个元素 |
| First < T源 > ( IEnumerable < T源 > , Func < T源 , bool > ) | 返回队列中满足指定条件的第一个元素 |
| FirstOrDefault < T源 > ( IEnumerable < T源 > ) | 返回队列的第一个元素;如果队列为 Empty,则返回默认值 |
| FirstOrDefault < T源 > ( IEnumerable < T源 > , T源 ) | 返回队列的第一个元素;如果队列为 Empty,则返回指定的默认值 |
| FirstOrDefault < T源 > ( IEnumerable < T源 > , Func < T源 , bool > ) | 返回队列中满足条件的第一个元素;如果未找到这样的元素,则返回默认值 |
| FirstOrDefault < T源 > ( IEnumerable < T源 > , Func < T源 , bool > , T源 ) | 返回队列中满足条件的第一个元素;如果未找到这样的元素,则返回指定的默认值 |
| Last < T源 > ( IEnumerable < T源 > ) | 返回队列的最后一个元素 |
| Last < T源 > ( IEnumerable < T源 > , Func < T源 , bool > ) | 返回队列中满足指定条件的最后一个元素 |
| LastOrDefault < T源 > ( IEnumerable < T源 > ) | 返回队列的最后一个元素;如果队列为 Empty,则返回默认值 |
| LastOrDefault < T源 > ( IEnumerable < T源 > , T源 ) | 返回队列的最后一个元素;如果队列为 Empty,则返回指定的默认值 |
| LastOrDefault < T源 > ( IEnumerable < T源 > , Func < T源 , bool > ) | 返回队列中满足条件的最后一个元素;如果未找到这样的元素,则返回默认值 |
| LastOrDefault < T源 > ( IEnumerable < T源 > , Func < T源 , bool > , T源 ) | 返回队列中满足条件的最后一个元素;如果未找到这样的元素,则返回指定的默认值 |
public static T源 First < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 );
public static T源 First < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , bool > 条件委托 );
public static T源? FirstOrDefault < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 );
public static T源 FirstOrDefault < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , T源 默认值 );
public static T源? FirstOrDefault < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , bool > 条件委托 );
public static T源 FirstOrDefault < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , bool > 条件委托 , T源 默认值 );
public static T源 Last < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 );
public static T源 Last < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , bool > 条件委托 );
public static T源? LastOrDefault < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 );
public static T源 LastOrDefault < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , T源 默认值 );
public static T源? LastOrDefault < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , bool > 条件委托 );
public static T源 LastOrDefault < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , bool > 条件委托 , T源 默认值 );参数
| 参数 | 类型 | 方法 | 注解 |
|---|---|---|---|
| T源 | T | 源 的数据类型 | |
| 源 | IEnumerable < T源 > | 欲返回元素的队列 | |
| 条件委托 | Func < T源 , bool > | 返回元素的条件 | |
| 默认值 | T源 | FirstOrDefault LastOrDefault | 当 源 为 Empty,或 条件委托 返回 false 的返回值 |
返回值
| 类型 | 方法 | 注解 |
|---|---|---|
| T源 | First Last | 当 队列 不为 null 或 Empty,返回 队列 的第一个或最后一个(符合条件的)元素 |
| T源 | FirstOrDefault LastOrDefault | 当 队列 不为 null,返回 队列 的第一个或最后一个(符合条件的)元素;若 队列 为 Empty 或没有元素符合 条件委托,返回指定的默认值 |
异常
| 异常 | 方法 | 注解 |
|---|---|---|
| ArgumentNullException | 源 或 条件委托 为 null | |
| InvalidOperationException | First Last | 源 为 Empty |
示例
以下示例展示了四个方法的用法:
IEnumerable < int > DLZhss = [ 10 , 20 , 30 , 21 , 14 , 19 , 35 , 26 , 17 ];
IEnumerable < int > DLZhss空 = [ ];
FF显示队列 ( "原始队列:" , DLZhss );
int zhs1 = DLZhss . First ( );
Console . WriteLine ( $"\nDLZhss . First ( ) = {zhs1}" );
int zhsH = DLZhss . Last ( );
Console . WriteLine ( $"\nDLZhss . Last ( ) = {zhsH}" );
int zhs1dayu20 = DLZhss . First ( x => x > 20 );
Console . WriteLine ( $"\nDLZhss . First ( x => x > 20 ) = {zhs1dayu20}" );
int zhsHdayu20 = DLZhss . Last ( x => x > 20 );
Console . WriteLine ( $"\nDLZhss . Last ( x => x > 20 ) = {zhsHdayu20}" );
int zhs非空1 = DLZhss . FirstOrDefault ( );
Console . WriteLine ( $"\nDLZhss . FirstOrDefault ( ) = {zhs非空1}" );
int zhs空1 = DLZhss空 . FirstOrDefault ( );
Console . WriteLine ( $"\nDLZhss空 . FirstOrDefault ( ) = {zhs空1}" );
int zhs非空100 = DLZhss . FirstOrDefault ( x => x > 100 );
Console . WriteLine ( $"\nDLZhss . FirstOrDefault ( x => x > 100 ) = {zhs非空100}" );
static void FF显示队列 ( string 说明 , IEnumerable < int > 队列 )
{
Console . WriteLine ( 说明 );
Console . WriteLine ( string . Join ( ',' , 队列 ) );
}备注
若不指定默认值且 T源 是引用类型或可空类型,对于 FirstOrDefault 和 LastOrDefault,其返回值可能是 null。永远不要指望 FirstOrDefault 和 LastOrDefault 的返回值一定是 源 中存在的元素,其返回值可能只是默认值而已。
对于未实现 IList< T >/IReadOnlyList < T >(没有索引),Last 和 LastOrDefault 只能遍历队列至最后一个元素才能确定返回值。
GroupBy
将队列中的元素按某种规则分组(每个组是一个 IEnumerable 对象或结果表达器返回值)。
重载
| 重载 | 注解 |
|---|---|
| GroupBy < T源 , T键 > ( IEnumerable < T源 > , Func < T源 , T键 > ) | 根据指定的键选择器分组队列中的元素 |
| GroupBy < T源 , T键 > ( IEnumerable < T源 > , Func < T源 , T键 > , IEqualityComparer < T键 > ) | 根据指定的键选择器以及比较器分组队列中的元素 |
| GroupBy < T源 , T键 , T元素 > ( IEnumerable < T源 > , Func < T源 , T键 > , Func < T源 , T元素 > ) | 根据键选择器分组队列中的元素,并使用元素表达器表达元素 |
| GroupBy < T源 , T键 , T元素 > ( IEnumerable < T源 > , Func < T源 , T键 > , Func < T源 , T元素 > , IEqualityComparer < T键 > ) | 根据键选择器和键比较器分组队列中的元素,并使用元素表达器表达元素 |
| GroupBy < T源 , T键 , T结果 > ( IEnumerable < T源 > , Func < T源 , T键 > , Func < T键 , IEnumerable < T源 > , T结果 > ) | 根据键选择器分组队列中的元素,并用结果表达器封装返回值 |
| GroupBy < T源 , T键 , T结果 > ( IEnumerable < T源 > , Func < T源 , T键 > , Func < T键 , IEnumerable < T源 > , T结果 > , IEqualityComparer < T键 > ) | 根据键选择器和键比较器分组队列中的元素,并使用结果表达器封装返回值 |
| GroupBy < T源 , T键 , T元素 , T结果 > ( IEnumerable < T源 > , Func < T源 , T键 > , Func < T源 , T元素 > , Func < T键 , IEnumerable < T元素 > , T结果 > ) | 根据键选择器分组队列中的元素,并使用元素表达器表达元素。并用结果表达器封装返回值 |
| GroupBy < T源 , T键 , T元素 , T结果 > ( IEnumerable < T源 > , Func < T源 , T键 > , Func < T源 , T元素 > , Func < T键 , IEnumerable < T元素 > , T结果 > , IEqualityComparer < T键 > ) | 根据键选择器和键比较器分组队列中的元素,并使用元素表达器表达元素。并用结果表达器封装返回值 |
public static System . Collections . Generic . IEnumerable < System . Linq . IGrouping < T键 , T源 > > GroupBy < T源 , T键 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , T键 > 键选择器 );
public static System . Collections . Generic . IEnumerable < System . Linq . IGrouping < T键 , T源 > > GroupBy < T源 , T键 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , T键 > 键选择器 , System . Collections . Generic . IEqualityComparer < T键 > 键比较器 );
public static System . Collections . Generic . IEnumerable < System . Linq . IGrouping < T键 , T元素 > > GroupBy < T源 , T键 , T元素 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , T键 > 键选择器 , Func < T源 , T元素 > 元素表达器 );
public static System . Collections . Generic . IEnumerable < System . Linq . IGrouping < T键 , T元素 > > GroupBy < T源 , T键 , T元素 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , T键 > 键选择器 , Func < T源 , T元素 > 元素表达器 , System . Collections . Generic . IEqualityComparer < T键 > 键比较器 );
public static System . Collections . Generic . IEnumerable < T结果 > GroupBy < T源 , T键 , T结果 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , T键 > 键选择器 , Func < T键 , System . Collections . Generic . IEnumerable < T源 > , T结果 > 结果表达器 );
public static System . Collections . Generic . IEnumerable < T结果 > GroupBy < T源 , T键 , T结果 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , T键 > 键选择器 , Func < T键 , System . Collections . Generic . IEnumerable < T源 > , T结果 > 结果表达器 , System . Collections . Generic . IEqualityComparer < T键 > 键比较器 );
public static System . Collections . Generic . IEnumerable < T结果 > GroupBy < T源 , T键 , T元素 , T结果 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , T键 > 键选择器 , Func < T源 , T元素 > 元素表达器 , Func < T键 , System . Collections . Generic . IEnumerable < T元素 > , T结果 > 结果表达器 );
public static System . Collections . Generic . IEnumerable < T结果 > GroupBy < T源 , T键 , T元素 , T结果 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , T键 > 键选择器 , Func < T源 , T元素 > 元素表达器 , Func < T键 , System . Collections . Generic . IEnumerable < T元素 > , T结果 > 结果表达器 , System . Collections . Generic . IEqualityComparer < T键 > 键比较器 );参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T键 | T | 键 的返回值类型 |
| T源 | T | 源 队列的元素类型 |
| 源 | IEnumerable < T源 > | 欲分组元素的队列 |
| 键选择器 | Func < T源 , T键 > | 提取每个元素的键的函数 |
| T元素 | T | 元素表达器 函数的返回值类型 |
| 元素表达器 | Func < T源 , T元素 > | 一个将每个源元素映射到 IGrouping < T键 , T元素 > 中元素的函数 |
| T结果 | T | 结果表达器 函数的返回值类型 |
| 结果表达器 | Func < T键 , IEnumerable < T元素 > , T结果 >(有元素表达器) Func < T键 , IEnumerable < T源 > , T结果 >(无元素表达器) | 一个用于从每个分组创建结果值的函数 |
| 键比较器 | IEqualityComparer < T键 > | 用于比较键值的比较器 |
返回值
| 有无结果表达器 | 类型 | 注解 |
|---|---|---|
| 无 | IEnumerable < IGrouping < T键 , T源 > >(无元素表达器) IEnumerable < IGrouping < T键 , T元素 > >(有元素表达器) | Visual Basic 中的 IEnumerable ( Of IGrouping ( Of T键 , T源 ) ) 或 IEnumerable ( Of IGrouping ( Of T键 , T元素 ) ),其中每个 IGrouping < T键 , T元素 > 对象都包含一组对象(对象的表达与是否有有效的元素表达器有关)和一个键 |
| 有 | IEnumerable < T结果 > | 一组类型为 T结果 的元素集合,其中每个元素都表示对一个组及其键的结果表达器的表达形式 |
异常
| 异常 | 注解 |
|---|---|
| ArgumentNullException | 源 或 键选择器 或 元素表达器 或 结果表达器 是 null |
示例
以下示例描述了如何自一个 int 队列中返回其偶数和奇数分组(最简单的 GroupBy):
List < int > DLZhss = [ 10 , 20 , 30 , 21 , 14 , 19 , 35 , 26 , 17 ];
FF显示队列 ( "原始队列:" , DLZhss );
var CHX = DLZhss . GroupBy < int , bool > ( FF整除2 );
foreach ( var z in CHX )
{
Console . WriteLine ( z . Key );
Console . WriteLine ( string . Join ( ',' , z ) );
}
static bool FF整除2 ( int 整数 )
{
if ( 整数 % 2 == 0 ) return true;
return false;
}以下示例是上一个示例的扩展,使用 元素表达器 表达了返回值的每一个组的每一个元素是否大于 20:
List < int > DLZhss = [ 10 , 20 , 30 , 21 , 14 , 19 , 35 , 26 , 17 ];
FF显示队列 ( "原始队列:" , DLZhss );
var CHX = DLZhss . GroupBy < int , bool , bool > ( FF整除2 , x => x > 20 );
foreach ( var z in CHX )
{
Console . WriteLine ( z . Key );
Console . WriteLine ( string . Join ( ',' , z ) );
}
static bool FF整除2 ( int 整数 )
{
if ( 整数 % 2 == 0 ) return true;
return false;
}以下示例展示了几个学生按年龄分组但表达其姓名的场景:
List < LEI学生 > XSs =
[
new LEI学生 { 姓名 = "刘飞飞" , 年龄 = 21 },
new LEI学生 { 姓名 = "梁美玉" , 年龄 = 22 },
new LEI学生 { 姓名 = "陈玉玲" , 年龄 = 22 },
new LEI学生 { 姓名 = "胡玉黛" , 年龄 = 23 },
];
FF显示队列 ( "原始队列:" , XSs );
var CHX = XSs . GroupBy < LEI学生 , uint , string > ( xs => xs . 年龄 , xs => xs . 姓名 );
foreach ( var xs in CHX )
{
Console . WriteLine ( xs . Key );
Console . WriteLine ( string . Join ( ',' , xs ) );
}
static void FF显示队列 ( string 说明 , IEnumerable < LEI学生 > 队列 )
{
Console . WriteLine ( 说明 );
Console . WriteLine ( string . Join ( " ; " , 队列 ) );
}
public class LEI学生
{
public required string 姓名 { get; set; }
public required uint 年龄 { get; set; }
public override string ToString ( )
{
return $"{姓名},年龄 {年龄} 岁";
}
}以下示例修改了上述示例的一小部分,使用了结果表达器使得结果成为一个元素而不是按键分组的队列:
var CHX = XSs . GroupBy < LEI学生 , uint , string , string > ( xs => xs . 年龄 , xs => xs . 姓名 , ( nl , xms ) => $"年龄 {nl} 岁,共有 {xms . Count ( )} 人,包括:{string . Join ( '、' , xms )}" );
foreach ( var xs in CHX )
{
Console . WriteLine ( xs );
}备注
在查询表达式语法中,group by(C#)或 Group By Into(Visual Basic)子句会转换为对 GroupBy 的调用。
此方法通过延迟执行来实现。其直接返回值是一个对象,该对象存储执行操作所需的所有信息。只有当通过直接调用对象的 GetEnumerator 方法,或在 C# 中使用 foreach、在 Visual Basic 中使用 For Each 对该对象进行枚举时,此方法所表示的查询才会执行。
未经过结果表达器封装的返回值是一个 IGrouping < T键 , T元素 > 对象集合,每个对象对应一个遇到的不同键。IGrouping < T键 , T元素 > 是一种 IEnumerable < T >,同时其元素还关联着一个键。
IGrouping < T键 , T元素 > 对象的生成顺序基于 源 中生成每个 IGrouping < T键 , T元素 > 第一个键的元素的顺序。分组中的元素会按照生成它们的元素在 源 中出现的顺序生成。
未指定 键比较器 或 键比较器 为 null 时默认的相等比较器 Default 用于比较键。
如果根据 键比较器 判定两个键相等,则将第一个键用作该分组的键。
GroupJoin
根据键的相等性关联正副两个队列的元素,并对结果进行分组。
重载
| 重载 | 注解 |
|---|---|
| GroupJoin < T正 , T副 , T键 , T结果 > ( IEnumerable < T正 > , IEnumerable < T副 > , Func < T正 , T键 > , Func < T副 , T键 > , Func < T正 , IEnumerable < T副 > , T结果 > ) | 根据键的相等性对两个队列的元素进行关联,并对结果进行分组。将使用默认的相等比较器来比较键 |
| GroupJoin < T正 , T副 , T键 , T结果 > ( IEnumerable < T正 > , IEnumerable < T副 > , Func < T正 , T键 > , Func < T副 , T键 > , Func < T正 , IEnumerable < T副 > , T结果 > , IEqualityComparer < T键 > ) | 根据键的相等性对两个队列的元素进行关联,并对结果进行分组。将使用指定的相等比较器来比较键 |
public static System . Collections . Generic . IEnumerable < T结果 > GroupJoin < T正 , T副 , T键 , T结果 > ( this System . Collections . Generic . IEnumerable < T正 > 正 , System . Collections . Generic . IEnumerable < T副 > 副 , Func < T正 , T键 > 正键选择器 , Func < T副 , T键 > 副键选择器 , Func < T正 , System . Collections . Generic . IEnumerable < T副 > , T结果 > 结果表达器 );
public static System . Collections . Generic . IEnumerable < T结果 > GroupJoin < T正 , T副 , T键 , T结果 > ( this System . Collections . Generic . IEnumerable < T正 > 正 , System . Collections . Generic . IEnumerable < T副 > 副 , Func < T正 , T键 > 正键选择器 , Func < T副 , T键 > 副键选择器 , Func < T正 , System . Collections . Generic . IEnumerable < T副 > , T结果 > 结果表达器 , System . Collections . Generic . IEqualityComparer < T键 >? 键比较器 );参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T结果 | T | 返回值的数据类型 |
| T正 T副 | T | 正队列的元素类型 副队列的元素类型 |
| T键 | T | 键选择器的返回值类型(即分组的依据) |
| 正 副 | IEnumerable < T正 > IEnumerable < T副 > | 欲连接的主队列 欲与主队列连接的队列 |
| 正键选择器 | Func < T正 , T键 > | 正队列的提取元素连接键的函数 |
| 副键选择器 | Func < T副 , T键 > | 副队列的提取元素连接键的函数 |
| 结果表达器 | Func < T正 , IEnumerable < T副 > , T结果 > | 根据正队列与副队列匹配元素创建的 T结果 元素类型的函数 |
| 键比较器 | IEqualityComparer < T键 >? | 用于比较键的比较器,null 则为 default |
返回值
| 类型 | 注解 |
|---|---|
| IEnumerable < T结果 > | 包含两个队列分组连接的 T结果 类型的元素的队列 |
异常
| 异常 | 注解 |
|---|---|
| ArgumentNullException | 正、副、正键选择器、副键选择器 或 结果表达器 为 null |
示例
以下示例连接了两个队列,主队列是个人物队列,副队列是个宠物队列(每个宠物包括其主人和种类),连接后仅描述其中养狗的主人:
List < LEI学生 > XSs =
[
new LEI学生 { 姓名 = "刘飞飞" , 年龄 = 21 },
new LEI学生 { 姓名 = "梁美玉" , 年龄 = 22 },
new LEI学生 { 姓名 = "陈玉玲" , 年龄 = 22 },
new LEI学生 { 姓名 = "胡玉黛" , 年龄 = 23 },
];
FF显示队列 ( "原始队列:" , XSs );
List < LEI宠物 > CWs =
[
new LEI宠物 { 姓名 = "shen" , 主人 = XSs [ 0 ] , 种类 = "狗" },
new LEI宠物 { 姓名 = "sao" , 主人 = XSs [ 0 ] , 种类 = "猫" },
new LEI宠物 { 姓名 = "miao" , 主人 = XSs [ 1 ] , 种类 = "狗" },
new LEI宠物 { 姓名 = "xiao" , 主人 = XSs [ 2 ] , 种类 = "猫" },
];
FF显示队列 ( "原始宠物队列:" , CWs );
var Gou学生 = XSs . GroupJoin (
CWs . Where ( 宠物 => 宠物 . 种类 == "狗" ), // 副队列(仅包含狗的主人)
学生 => 学生 . 姓名, // 主键
宠物 => 宠物 . 主人 . 姓名, // 副键
( 学生 , DL狗 ) => new // 结果表达器
{
xm = 学生 . 姓名,
狗 = string . Join ( '、' , DL狗 . Select ( c => c . 姓名 ) )
}
);
FF显示队列 ( "连接后的队列:" , Gou学生 );
static void FF显示队列 < T > ( string 说明 , IEnumerable < T > 队列 )
{
Console . WriteLine ( "==================== " + 说明 + " ====================" );
int 序号 = 1;
foreach ( var 项 in 队列 )
{
Console . WriteLine ( $"第 {序号} 项:{项}" );
序号++;
}
}
public class LEI学生
{
public required string 姓名 { get; set; }
public required uint 年龄 { get; set; }
public override string ToString ( )
{
return $"{姓名},年龄 {年龄} 岁";
}
}
public class LEI宠物
{
public required string 姓名 { get; set; }
public required LEI学生 主人 { get; set; }
public required string 种类 { get; set; }
public override string ToString ( )
{
return $"{姓名} → {主人},养了个 {种类}";
}
}备注
此方法通过延迟执行来实现。其直接返回值是一个对象,该对象包含执行该操作所需的所有信息。只有当通过直接调用对象的 GetEnumerator 方法,或在 C# 中使用 foreach、在 Visual Basic 中使用 For Each 对该对象进行枚举时,此方法所表示的查询才会执行。
默认相等比较器 Default 用于对键进行哈希处理和比较。
GroupJoin 会生成分层结果,这意味着来自 主 的元素会与来自 副 的匹配元素集合进行配对。GroupJoin 使你能够基于 副 每个元素的完整匹配集来构建结果。
注意:
如果对于 主 的某个给定元素,副 中不存在相关元素,则该元素的匹配序列将为空,但仍会出现在结果中。
结果表达器 函数会针对每个 主 元素调用一次,同时传入与该 主 元素匹配的所有 副 元素的集合。这与 Join 方法不同,在 Join 方法中,结果选择器函数会作用于由一个 主 元素和一个 副 元素组成的元素对。
GroupJoin 会保留 主 中元素的顺序,并且对于 主 中的每个元素,也会保留从 副 中匹配到的元素的顺序。
GroupJoin 在传统关系数据库术语中没有直接对应的概念。不过,该方法实现了内连接和左外连接的超集。这两种操作都可以通过分组连接来表示。
在查询表达式语法中,join……into(C#)或 Group Join(Visual Basic)子句会转换为对 GroupJoin 的调用。
Index
返回一个队列(与方法名相反,不可索引),该对象将元素的索引合并到元组中。 public static System . Collections . Generic . IEnumerable < ( int Index , T源 Item ) > Index < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 );
参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T源 | T | 源队列 的元素类型 |
| 源 | IEnumerable < T源 > | 欲生成索引的队列 |
返回值
| 类型 | 注解 |
|---|---|
| IEnumerable < ( int Index , T源 Item ) > | 一个由元组组成的队列,元组由 0 起始的索引和 源 中的项目组成 |
异常
| 异常 | 注解 |
|---|---|
| ArgumentNullException | 源 为 null |
示例
以下示例创建了一个 string 队列,并使用 Index 生成其索引元组队列:
List < string > ZFCs =
[
"我和你",
"你和我",
"我和她",
"她和你",
];
FF显示队列 ( "原始队列:" , ZFCs );
var suoyin = ZFCs . Index ( );
FF显示队列 ( "索引后的队列:" , suoyin );
var sy = suoyin . ToList ( ); // Index 的返回值仅是可枚举对象,但不可索引,必须通过 ToList 或 ToAray 生成新的可索引对象,才能随机访问其某个元素
Console . Write ( $"Index {sy [ 0 ] . Index}," );
Console . WriteLine ( $"Item = {sy [ 0 ] . Item}" );
var ( Index , Item ) = suoyin . ElementAt ( 2 ); // 但可使用 ElementAt 访问其某个元素
Console . Write ( $"Index {Index}," );
Console . WriteLine ( $"Item = {Item}" );
static void FF显示队列 < T > ( string 说明 , IEnumerable < T > 队列 )
{
Console . WriteLine ( "==================== " + 说明 + " ====================" );
int 序号 = 1;
foreach ( var 项 in 队列 )
{
Console . WriteLine ( $"第 {序号} 项:{项}" );
序号++;
}
}备注
如示例,其返回值不可索引,不可随机访问。仅仅是一个可枚举对象。
返回值的每个元素都由一个整数(Index,0 起始,最大值 Count - 1),和 源队列 中的每一个元素值(Item)组成。
InfiniteSequence
生成一个以指定起始值起始的无限队列,并生成每个值均比前一个值差指定步长的后续数值。 public static System . Collections . Generic . IEnumerable < T > InfiniteSequence < T > ( T起始 , T步长 ) where T : System . Numerics . IAdditionOperators < T , T , T >;
参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T | T | 返回值的元素类型(必须实现 IAdditionOperators < TSelf , TSelf , TSelf > 接口的类型 |
| T起始 | T | 返回队列首元素的起始点 |
| T步长 | T | 下一个值对于前一个值的递增(递减)的数值 |
返回值
| 类型 | 注解 |
|---|---|
| IEnumerable < T > | 一个包含无限元素的队列(除非你限制了该队列的元素数,不要尝试处理该队列) |
示例
以下示例返回了一个 int 队列,只取了其前 100 个元素。由于它是无限的,计算机实际无法处理该队列,所以使用了 Take 方法:
var DL无限 = Enumerable . InfiniteSequence ( 20 , 3 ) . Take ( 100 );
FF显示队列 ( "无限的:" , DL无限 );
static void FF显示队列 < T > ( string 说明 , IEnumerable < T > 队列 )
{
Console . WriteLine ( "==================== " + 说明 + " ====================" );
int 序号 = 1;
foreach ( var 项 in 队列 )
{
Console . WriteLine ( $"第 {序号} 项:{项}" );
序号++;
}
}备注
它确实生成一个无限元素数的队列,但没有实际操作。只有当 foreach(C#)或 For…Each(Visual Basic)等方法执行时,它才会真正执行。由于是无限的,一定会产生 内存溢出异常,所以一定要用 Take 等限制条件限制其返回的队列的长度。
不要尝试操作该方法的返回值,除非你对其元素数进行了限制。相对于 Range,它最大的好处是不需要知道最后一个元素是什么,但必须知道你需要的元素数。
Intersect
返回两个队列的交集(HashSet 底层),即主队列中存在且副队列中也存在的元素(去重)组成的队列。
重载
| 重载 | 注解 |
|---|---|
| Intersect < T源 > ( IEnumerable < T源 > , IEnumerable < T源 > ) | 按默认的相等比较器比较元素,生成两个队列的交集 |
| Intersect < T源 > ( IEnumerable < T源 > , IEnumerable < T源 > , IEqualityComparer < T源 > ) | 按指定的相等比较器比较元素,生成两个队列的交集 |
public static System . Collections . Generic . IEnumerable < T源 > Intersect < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 主队列 , System . Collections . Generic . IEnumerable < T源 > 副队列 );
public static System . Collections . Generic . IEnumerable < T源 > Intersect < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 主队列 , System . Collections . Generic . IEnumerable < T源 > 副队列 , System . Collections . Generic . IEqualityComparer < T源 >? 比较器 );参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T源 | T | 欲求合集的两个队列的元素类型 |
| 主队列 副队列 | IEnumerable < T源 > | 欲求合集的两个队列 |
| 比较器 | IEqualityComparer < T源 >? | 值 的 比较器,null 或未指定则为默认比较器 |
返回值
| 类型 | 注解 |
|---|---|
| IEnumerable < T源 > | 包含两个队列的交集的元素的队列 |
异常
| 异常 | 注解 |
|---|---|
| ArgumentNullException | 主队列 和/或 副队列 是 null |
示例
以下示例展示了两个 int 队列的交集:
var DL无限 = Enumerable . InfiniteSequence ( 20 , 3 ) . Take ( 100 );
List < int > DL副 = [ 25, 26 , 27 , 28 ];
var DL交集 = DL无限 . Intersect ( DL副 );
FF显示队列 ( "交集:" , DL交集 );
static void FF显示队列 < T > ( string 说明 , IEnumerable < T > 队列 )
{
Console . WriteLine ( "==================== " + 说明 + " ====================" );
int 序号 = 1;
foreach ( var 项 in 队列 )
{
Console . WriteLine ( $"第 {序号} 项:{项}" );
序号++;
}
}注解
此方法是使用延迟执行实现的。即时返回值是一个对象,用于存储执行操作所需的所有信息。除非通过直接调用其 GetEnumerator 方法或在 foreach(C#)或在 For Each(Visual Basic)中使用来枚举对象,否则不会执行此方法表示的查询。
主队列 和 副队列 的交集定义为包含 主队列 的所有元素的集,这些元素也包含在 副队列 中,但没有其他元素。
枚举此方法返回的对象时, Intersect 将按照两个队列中出现的顺序生成不同的元素。
比较器 如果是 null 或未指定,则使用默认相等比较器 Default 来比较值。
IntersectBy
重载
| 名称 | 描述 |
|---|---|
| IntersectBy < T1 , T2 > ( IEnumerable < T1 > , IEnumerable < T2 > , Func < T1 , T2 > ) | 根据指定的键选择器函数生成两个序列的队列交集 |
| IntersectBy < T1 , T2 > ( IEnumerable < T1 > , IEnumerable < T2 > , Func < T1 , T2 > , IEqualityComparer < T2 > ) | 根据指定的键选择器函数和键比较器生成两个序列的队列交集 |
public static System . Collections . Generic . IEnumerable < T1 > IntersectBy < T1 , T2 > ( this System . Collections . Generic . IEnumerable < T1 > 首 , System . Collections . Generic . IEnumerable < T2 > 次 , Func < T1 , T2 > 键生成器 );
public static System . Collections . Generic . IEnumerable < T1 > IntersectBy < T1 , T2 > ( this System . Collections . Generic . IEnumerable < T1 > 首 , System . Collections . Generic . IEnumerable < T2 > 次 , Func < T1 , T2 > 键生成器 , System . Collections . Generic . IEqualityComparer < T2 >? 键比较器 );参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T1 | T | 首 队列的元素类型 |
| T2 | T | 次 队列的元素类型 |
| 首 | IEnumerable < T1 > | 欲求交集的第一个队列(实际比较的是键生成器生成的键) |
| 次 | IEnumerable < T2 > | 欲求交集的第二个队列 |
| 键生成器 | Func < T1 , T2 > | 为每个元素生成键的函数 |
| 键比较器 | IEqualityComparer < T2 >? | 比较键的 比较器 |
返回值
| 类型 | 注解 |
|---|---|
| IEnumerable < T1 > | 包含交集(首 中的部分元素,其生成的键存在于 次 队列中)的队列 |
异常
| 异常 | 注解 |
|---|---|
| ArgumentNullException | 首 和/或 次 是 null |
示例
以下示例中 首 是一个无限队列中的前 20 项,次 是一个等差数列,键选择器是整除 2,意即:首 队列中哪个元素整除 2 的结果在 次 队列中出现。
var DL无限 = Enumerable . InfiniteSequence ( 20 , 3 ) . Take ( 20 );
List < int > DL副 = [ 12 , 13 , 14 , 15 ];
var DL交集 = DL无限 . IntersectBy < int , int > ( DL副 , x => x / 2 );
FF显示队列 ( "交集:" , DL交集 );
static void FF显示队列 < T > ( string 说明 , IEnumerable < T > 队列 )
{
Console . WriteLine ( "==================== " + 说明 + " ====================" );
int 序号 = 1;
foreach ( var 项 in 队列 )
{
Console . WriteLine ( $"第 {序号} 项:{项}" );
序号++;
}
}备注
此方法通过延迟执行来实现。其直接返回值是一个对象,该对象存储执行操作所需的所有信息。只有当通过直接调用对象的 GetEnumerator 方法,或在 C# 中使用 foreach、在 Visual Basic 中使用 For Each 对该对象进行枚举时,此方法所表示的查询才会执行。
两个队列 首 和 次 的交集被定义为这样的集合:它包含 首 中部分元素,其按键生成器生成的键值,也出现在 次 中。例如示例中的 26 和 29,其整除 2 的结果 13、14 在 DL副 中。
当此方法返回的对象被枚举时,IntersectBy 会按照它们在 首 中出现的顺序,生成同时存在于两个序列中的不同元素。
如果 键比较器 为 null,则使用默认的相等比较器 Default 来比较键值。
Join
基于匹配的键关联两个队列的元素。
重载
| 重载 | 注解 |
|---|---|
| Join < T主 , T副 , T键 , T结果 > ( IEnumerable < T主 > , IEnumerable < T副 > , Func < T主 , T键 > , Func < T副 , T键 > , Func < T主 , T副 , T结果 > ) | 基于匹配的键对两个队列的元素进行关联。将使用默认的相等比较器来比较键 |
| Join < T主 , T副 , T键 , T结果 > ( IEnumerable < T主 > , IEnumerable < T副 > , Func < T主 , T键 > , Func < T副 , T键 > , Func < T主 , T副 , T结果 > , IEqualityComparer < T键 > ) | 基于匹配的键对两个队列的元素进行关联。将使用指定的相等比较器来比较键 |
public static System . Collections . Generic . IEnumerable < T结果 > Join < T主 , T副 , T键 , T结果 > ( this System . Collections . Generic . IEnumerable < T主 > 主 , System . Collections . Generic . IEnumerable < T副 > 副 , Func < T主 , T键 > 主键生成器 , Func < T副 , T键 > 副键生成器 , Func < T主 , T副 , T结果 > 结果生成器 );
public static System . Collections . Generic . IEnumerable < T结果 > Join < T主 , T副 , T键 , T结果 > ( this System . Collections . Generic . IEnumerable < T主 > 主 , System . Collections . Generic . IEnumerable < T副 > 副 , Func < T主 , T键 > 主键生成器 , Func < T副 , T键 > 副键生成器 , Func < T主 , T副 , T结果 > 结果生成器 , System . Collections . Generic . IEqualityComparer < T键 >? 比较器 );参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T结果 | T | 结果生成器生成队列的元素类型 |
| T主 | T | 欲连接的主队列的元素类型 |
| T副 | T | 欲连接的副队列的元素类型 |
| T键 | T | 主键生成器 和 副键生成器 的返回值类型 |
| 主 副 | IEnumerable < T主 > IEnumerable < T副 > | 欲连接的两个队列 |
| 主键生成器 副键生成器 | Func <T 主 , T 键> Func <T 副 , T 键> | 自 主队列 和 副队列 中每个元素提取连接键的函数 |
| 结果生成器 | Func < T 主 , T 副 , T 结果 > | 用于自两个队列匹配元素中创建结果元素的函数 |
| 比较器 | IEqualityComparer < T键 >? | 用于比较 主键 和 副键 的比较器,null 或未指定使用 default 比较器 |
返回值
| 类型 | 注解 |
|---|---|
| IEnumerable < T结果 > | 包含自两个队列匹配元素中创建结果元素的可枚举对象 |
异常
| 异常 | 注解 |
|---|---|
| ArgumentNullException | 主 或 副 或 主键生成器 或 副键生成器 或 结果生成器 是 null |
示例
以下示例创建了一个学生的队列,又创建了一个官职的队列,并 Join 学生队列的官职(记录编号即可)和官职队列的官号,由于没有为官号为 0 的学生安排官名,也就是说一个普通学生,所以输出结果仅仅是当官的:
List < LEI学生 > XSs =
[
new LEI学生 { 官职 = 1 , 姓名 = "赵老大" },
new LEI学生 { 官职 = 2 , 姓名 = "钱老二" },
new LEI学生 { 官职 = 0 , 姓名 = "孙老三" },
new LEI学生 { 官职 = 0 , 姓名 = "李老四" },
new LEI学生 { 官职 = 1 , 姓名 = "周老三" },
new LEI学生 { 官职 = 0 , 姓名 = "吴老六" },
new LEI学生 { 官职 = 3 , 姓名 = "郑老七" },
];
List < LEI官职 > Guans =
[
new LEI官职 { 官号 = 1 , 官名 = "班长" },
new LEI官职 { 官号 = 2 , 官名 = "副班长" },
new LEI官职 { 官号 = 3 , 官名 = "学习委员" },
];
IEnumerable < string > XS当官的 = XSs . Join ( Guans , xs => xs .官职 , g => g .官号 , ( xs , gz ) => $"{xs . 姓名} → {gz .官名}" );
FF显示队列 ( "当官的:" , XS当官的 );
public class LEI学生
{
public required string 姓名 { get; set; }
public required uint 官职 { get; set; }
}
public class LEI官职
{
public required string 官名 { get; set; }
public required uint 官号 { get; set; }
}备注
此方法通过延迟执行来实现。其直接返回值是一个对象,该对象存储执行该操作所需的所有信息。只有当通过直接调用对象的 GetEnumerator 方法,或在 C# 中使用 foreach、在 Visual Basic 中使用 For Each 对该对象进行枚举时,此方法所表示的查询才会执行。
默认的相等比较器 Default 用于对键进行哈希处理和比较。
连接指的是基于一个公共键关联两个信息源元素的操作。连接在一个方法调用中将两个信息源以及用于匹配它们的键整合在一起。这与 SelectMany 的用法不同,后者需要多个方法调用来执行相同的操作。
Join 会保留 T主 中元素的顺序,并且对于其中每个元素,也会保留 T副 中匹配元素的顺序。
在查询表达式语法中,join(C#)或 Join(Visual Basic)子句会转换为对 Join 方法的调用。
在关系数据库术语中,Join 方法实现了内等值连接。“内连接”意味着只有那些在 主 中与 副 存在匹配项的元素才会被包含在结果中。“等值连接”是一种对键进行相等性比较的连接操作。左外连接操作没有专用的标准查询运算符,但可通过 GroupJoin 方法实现。
LeftJoin 和 RightJoin
重载
| 重载 | 注解 |
|---|---|
| LeftJoin < T主 , T副 , T键 , T结果 > ( IEnumerable < T主 > , IEnumerable < T副 > , Func < T主 , T键 > , Func < T副 , T键 > , Func < T主 , T副 , T结果 > ) | 基于匹配的键对两个队列的元素进行关联。将使用默认的相等比较器来比较键 |
| LeftJoin < T主 , T副 , T键 , T结果 > ( IEnumerable < T主 > , IEnumerable < T副 > , Func < T主 , T键 > , Func < T副 , T键 > , Func < T主 , T副 , T结果 > , IEqualityComparer < T键 > ) | 基于匹配的键关联两个队列的元素。将使用指定的相等比较器来比较键 |
| RightJoin < T主 , T副 , T键 , T结果 > ( IEnumerable < T主 > , IEnumerable < T副 > , Func < T主 , T键 > , Func < T副 , T键 > , Func < T主 , T副 , T结果 > ) | 基于匹配的键对两个队列的元素进行关联。将使用默认的相等比较器来比较键 |
| RightJoin < T主 , T副 , T键 , T结果 > ( IEnumerable < T主 > , IEnumerable < T副 > , Func < T主 , T键 > , Func < T副 , T键 > , Func < T主 , T副 , T结果 > , IEqualityComparer < T键 > ) | 基于匹配的键关联两个队列的元素。将使用指定的相等比较器来比较键 |
public static System . Collections . Generic . IEnumerable < T结果 > LeftJoin < T主 , T副 , T键 , T结果 > ( this System . Collections . Generic . IEnumerable < T主 > 主 , System . Collections . Generic . IEnumerable < T副 > 副 , Func < T主 , T键 > 主键生成器 , Func < T副 , T键 > 副键生成器 ,
Func < T主 , T副? , T结果 > 结果生成器 );
public static System . Collections . Generic . IEnumerable < T结果 > LeftJoin < T主 , T副 , T键 , T结果 > ( this System . Collections . Generic . IEnumerable < T主 > 主 , System . Collections . Generic . IEnumerable < T副 > 副 , Func < T主 , T键 > 主键生成器 , Func < T副 , T键 > 副键生成器 , Func < T主 , T副? , T结果> 结果生成器 , System . Collections . Generic . IEqualityComparer < T键 >? 比较器 );
public static System . Collections . Generic . IEnumerable < T结果 > RightJoin < T主 , T副 , T键 , T结果 > ( this System . Collections . Generic . IEnumerable < T主 > 主 , System . Collections . Generic . IEnumerable < T副 > 副 , Func < T主 , T键 > 主键生成器 , Func < T副 , T键 > 副键生成器 ,
Func < T主? , T副 , T结果 > 结果生成器 );
public static System . Collections . Generic . IEnumerable < T结果 > RightJoin < T主 , T副 , T键 , T结果 > ( this System . Collections . Generic . IEnumerable < T主 > 主 , System . Collections . Generic . IEnumerable < T副 > 副 , Func < T主 , T键 > 主键生成器 , Func < T副 , T键 > 副键生成器 , Func < T主? , T副 , T结果> 结果生成器 , System . Collections . Generic . IEqualityComparer < T键 >? 比较器 );参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T结果 | T | 结果生成器的返回值的元素类型 |
| T主 T副 | T | 主队列 和 副队列 的元素类型 |
| T键 | T | 主键生成器 和 副键生成器 的返回值类型 |
| 主 | IEnumerable < T主 > | 连接的主队列 |
| 副 | IEnumerable < T副 > | 连接的副队列 |
| 主键生成器 副键生成器 | Func < T主 , T键 > Func < T副 , T键 > | 根据 主队列 和 副队列 的每个元素生成连接键的函数 |
| 结果生成器 | Func < T主 , T副? , T结果 >(LeftJoin) Func < T主? , T副 , T结果 >(RightJoin) | 依据匹配元素创建结果元素的函数 |
| 比较器 | IEqualityComparer < T键 >? | 用于比较键的比较器,null 或未指定则为 default |
返回值
| 类型 | 注解 |
|---|---|
| IEnumerable < T结果 > | 一个包含每个匹配结果的可枚举对象 |
异常
| 异常 | 注解 |
|---|---|
| ArgumentNullException | 主 或 副 或 主键生成器 或 副键生成器 或 结果生成器 是 null |
示例
以下示例创建了一个学生和官职的队列,从而描述每个学生的官职或每个官职的学生:
List < LEI学生 > XSs =
[
new LEI学生 { 官职 = 1 , 姓名 = "赵老大" },
new LEI学生 { 官职 = 2 , 姓名 = "钱老二" },
new LEI学生 { 官职 = 0 , 姓名 = "孙老三" },
new LEI学生 { 官职 = 0 , 姓名 = "李老四" },
new LEI学生 { 官职 = 1 , 姓名 = "周老三" },
new LEI学生 { 官职 = 0 , 姓名 = "吴老六" },
new LEI学生 { 官职 = 3 , 姓名 = "郑老七" },
];
List < LEI官职 > Guans =
[
new LEI官职 { 官号 = 1 , 官名 = "班长" },
new LEI官职 { 官号 = 2 , 官名 = "副班长" },
new LEI官职 { 官号 = 3 , 官名 = "学习委员" },
new LEI官职 { 官号 = 4 , 官名 = "体育委员" },
];
IEnumerable < string > XG1 = XSs . LeftJoin ( Guans , xs => xs .官职 , g => g .官号 , ( xs , gz ) => $"{(xs != null ? xs . 姓名 : "无")} → {(gz != null ? gz . 官名 : "无")}" );
FF显示队列 ( "学生为主 LeftJoin:" , XG1 );
IEnumerable < string > XG2= XSs . RightJoin ( Guans , xs => xs .官职 , g => g .官号 , ( xs , gz ) => $"{(xs != null ? xs . 姓名 : "无")} → {(gz != null ? gz . 官名 : "无")}" );
FF显示队列 ( "学生为主 RightJoin:" , XG2 );
IEnumerable < string > XG3 = Guans . LeftJoin ( XSs , g => g .官号 , xs=> xs .官职 , ( gz , xs ) => $"{(xs != null ? xs . 姓名 : "无")} → {(gz != null ? gz . 官名 : "无")}" );
FF显示队列 ( "官职为主 LeftJoin:" , XG3 );
IEnumerable < string > XG4= Guans . RightJoin ( XSs , g => g .官号 , xs=> xs .官职 , ( gz , xs ) => $"{(xs != null ? xs . 姓名 : "无")} → {(gz != null ? gz . 官名 : "无")}" );
FF显示队列 ( "官职为主 RightJoin:" , XG4 );
static void FF显示队列 < T > ( string 说明 , IEnumerable < T > 队列 )
{
Console . WriteLine ( "==================== " + 说明 + " ====================" );
int 序号 = 1;
foreach ( var 项 in 队列 )
{
Console . WriteLine ( $"第 {序号} 项:{项}" );
序号++;
}
}备注
此方法通过延迟执行来实现。其直接返回值是一个对象,该对象存储执行该操作所需的所有信息。只有当通过直接调用对象的 GetEnumerator 方法,或在 C# 中使用 foreach、在 Visual Basic 中使用 For Each 对该对象进行枚举时,此方法所表示的查询才会执行。
默认或 null 的相等比较器 Default 用于对键进行哈希处理和比较。
连接指的是基于一个公共关键字关联两个信息源元素的操作。
LeftJoin 和 RightJoin 方法可在一次调用中将两个信息源及其用于匹配的键关联在一起。
在关系数据库术语中,LeftJoin 和 RightJoin 方法实现了外部左等值和外部右等值连接。作为外连接,必须使用处理 null 值的方法,以避免 NullReferenceException,因为 主/副 队列可能没有匹配 副/主 队列中所有元素的元素,例如示例中的某些学生不当官,或“体育委员”没人当等。示例中使用了统一的 null 条件运算符和 null 合并运算符来处理可能为 null 的值的方法。实际上,LeftJoin 一定返回主队列的所有元素,副队列元素可能为 null(例如不当官的);RightJoin 一定返回副队列的所有元素,主队列元素可能为 null(例如体育委员没人当)。因此必须根据连接类型处理相应的 null 值。
“左外连接”指无论在 副 队列中是否找到匹配元素,主 队列的元素都会被返回;“右外连接”指无论在 主 队列中是否找到匹配元素,副 队列的元素都会被返回。
A LeftJoin B = B RightJoin A
A RightJoin B = B LeftJoin A
“等值连接”是一种连接操作,其中对键进行相等性比较。
内连接(即结果中仅包含在另一序列中存在匹配项的元素)可通过 Join 方法实现。
Max 和 Min
返回一个队列中的最大值和最小值(必须由值类型或比较选择器返回值类型,即实现 IComparable < T > 接口)。
重载
| 重载 | 注解 |
|---|---|
| Max ( IEnumerable < T > ) | 返回 T 类型的队列中的最大值(T 必须实现 IComparable < T > 接口) |
| Min ( IEnumerable < T > ) | 返回 T 类型的队列中的最小值(T 必须实现 IComparable < T > 接口) |
| Max ( IEnumerable < T > , IComparer < T > ) | 返回 T 类型的队列中的最大值(T 必须实现 IComparable < T > 接口,使用指定比较器) |
| Min ( IEnumerable < T > , IComparer < T > ) | 返回 T 类型的队列中的最小值(T 必须实现 IComparable < T > 接口,使用指定比较器) |
| Max ( IEnumerable < Nullable < T > > ) | 返回 T 类型的队列中的最大值(T 仅限值类型,可能是 null,即源队列是 Empty 或仅包含 null) |
| Min ( IEnumerable < Nullable < T > > ) | 返回 T 类型的队列中的最小值(T 仅限值类型,可能是 null,即源队列是 Empty 或仅包含 null) |
| Max < T源 , T比较元素 > ( IEnumerable < T源 > , Func < T源 , T比较元素 > ) | 对队列中的每个元素调用比较选择器,并返回选择结果的最大值(T比较元素 必须实现 IComparable < T > 接口) |
| Min < T源 , T比较元素 > ( IEnumerable < T源 > , Func < T源 , T比较元素 > ) | 对队列中的每个元素调用比较选择器,并返回选择结果的最小值(T比较元素 必须实现 IComparable < T > 接口) |
| Max < T > ( IEnumerable < T > , Func < T , IComparable > ) | 对队列中的每个元素调用比较选择器,并返回选择结果的最大值(比较选择器的返回值 必须实现 IComparable < T > 接口) |
| Min < T > ( IEnumerable < T > , Func < T , IComparable > ) | 对队列中的每个元素调用比较选择器,并返回选择结果的最小值(比较选择器的返回值 必须实现 IComparable < T > 接口) |
public static T Max < T > ( this System . Collections . Generic . IEnumerable < T > 队列 );
public static T Min < T > ( this System . Collections . Generic . IEnumerable < T > 队列 );
public static T Max < T > ( this System . Collections . Generic . IEnumerable < T > 队列 , System . Collections . Generic . IComparer < T > 比较器 );
public static T Min < T > ( this System . Collections . Generic . IEnumerable < T > 队列 , System . Collections . Generic . IComparer < T > 比较器 );
public static System . Nullable < T > Max < T > ( this System . Collections . Generic . IEnumerable < System . Nullable < T > > 队列 );
public static System . Nullable < T > Min < T > ( this System . Collections . Generic . IEnumerable < System . Nullable < T > > 队列 );
public static T结果 Max < T源 , T比较元素 > ( this System . Collections . Generic . IEnumerable < T源 > 队列 , System . Func < T源 , T比较元素 > 比较选择器 );
public static T结果 Min < T源 , T比较元素 > ( this System . Collections . Generic . IEnumerable < T源 > 队列 , System . Func < T源 , T比较元素 > 比较选择器 );参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T T源 | T | 源队列 的元素类型(不指定转换函数,即为结果的类型),必须实现 IComparable 或 IComparable < T >,如果不指定 转换函数 的话 |
| 源 | IEnumerable < T源 > IEnumerable < T > | 欲求极值的队列 |
| 比较器 | IComparer < T > | 对于元素的大小的比较器 |
| T比较元素 | T | 比较选择器返回值的类型,必须实现 IComparable 或 IComparable < T > |
| 比较选择器 | Func < T源 , T比较元素 > | 如果指定该函数,返回值的类型为 T比较元素,实际最大值和最小值是函数返回值的极值 |
返回值
| 方法 | 类型 | 注解 |
|---|---|---|
| 返回值不可空(无比较选择器) | T 或 T源 | 与 源队列 元素类型相同的,队列中的极值 |
| 返回值不可空(有比较选择器) | T比较元素 | 队列中的极值(被比较选择器选择成 T比较元素) |
| 返回值可空(无比较选择器) | T 或 T源 | 与 源队列 元素类型相同的,队列中的极值。仅限于 源队列 是 Empty,或仅由元素 null(可以是引用类型)组成,可以是 null |
| 返回值可空(有比较选择器) | T比较元素 | 队列中的极值(比较选择器转换后的)。仅限于 源队列 的元素被 比较选择器 转换后是 Empty,或仅由元素 null(可以是引用类型)组成,可以是 null |
异常
| 异常 | 注解 |
|---|---|
| ArgumentException | 有元素(可以是被 比较选择器 转换后的)不实现 IComparable < T > 或 IComparable,或指定的比较器与元素不匹配(仅限于没有参数和仅提供 比较器 的重载) |
| ArgumentNullException | 源 或 比较选择器 为 null |
| InvalidOperationException | 返回值不可空时,队列没有任何元素(Empty,可以是被 比较选择器 转换后的) |
示例
以下示例展示了一个 int 队列中的极值:
List < int > DLZhss =
[
5 , 8 , 15 , 7 , 3
];
int D = DLZhss . Max ( );
int X = DLZhss . Min ( );
FF显示队列 ( "源队列:" , DLZhss );
Console . WriteLine ( $"队列中的极大值:{D};队列中的极小值:{X}" );
static void FF显示队列 < T > ( string 说明 , IEnumerable < T > 队列 )
{
Console . WriteLine ( "==================== " + 说明 + " ====================" );
Console . WriteLine ( string . Join ( ',' , 队列 ) );
}下面的示例展示了自定义类的 IComparable 接口的实现,一群小妹妹(她们只关心自己的体重):
List < LEI妹妹 > DL妹妹s =
[
new ( "孙小美" , 52.5 ),
new ( "王晓华" , 86.7 ),
new ( "张晓敏" , 51 ),
];
LEI妹妹? D = DL妹妹s . Max ( );
LEI妹妹? X = DL妹妹s . Min ( );
FF显示队列 ( "源队列:" , DL妹妹s );
Console . WriteLine ( $"队列中的极大值:{D};队列中的极小值:{X}" );
public class LEI妹妹 ( string 姓名 , double 体重 ) : IComparable < LEI妹妹 >
{
public string 姓名 { get; set; } = 姓名;
public double 体重 { get; set; } = 体重;
public int CompareTo ( LEI妹妹? other )
{
if ( other == null ) return -1;
return 体重 . CompareTo ( other . 体重 );
}
public override string ToString ( )
{
return $"{姓名},重 {体重} 公斤";
}
}下面的代码修改自上一个示例,使用了 比较选择器。描述一群小妹妹向你示爱,你想选择一个能抱得动的(结婚嘛,懂得)。于是只关心体重极大值(你只关心居然有妹妹这么重)和极小值是谁(管她多重,抱不动就锻炼身体去吧):
double Dmm = DL妹妹s . Max ( m => m . 体重 ); // 妹妹指定按体重排序,返回值就是体重(double)
LEI妹妹? Xmm = DL妹妹s . Min ( ); // 妹妹默认就是按体重排序,但返回值是个对象
FF显示队列 ( "源队列:" , DL妹妹s );
Console . WriteLine ( $"队列中的体重极大值:{Dmm};队列中的体重极小的妹妹:{Xmm! . 姓名}" ); // 你只是想欣赏体重最大的到底多重,但想知道体重最小的是谁以下示例描述了三个妹妹的 BMI,体重 ÷ ( 身高² )。由于 LEI妹妹 没有实现 IComparable 接口,因此必须用 比较选择器 来明确欲比较的内容,即她们的 BMI:
List < LEI妹妹 > DL妹妹s =
[
new ( "孙小美" , 52.5 , 1.56 ),
new ( "王晓华" , 86.7 , 1.73 ),
new ( "张晓敏" , 51 , 1.58 ),
];
double D = DL妹妹s . Max ( m => ( m . 体重 / ( Math . Pow ( m . 身高 , 2 ) ) ) );
double X = DL妹妹s . Min ( m => ( m . 体重 / ( Math . Pow ( m . 身高 , 2 ) ) ) );
FF显示队列 ( "源队列:" , DL妹妹s );
Console . WriteLine ( $"队列中的 BMI 极大值:{D};队列中的 BMI 极小值:{X}" );
static void FF显示队列 < T > ( string 说明 , IEnumerable < T > 队列 )
{
Console . WriteLine ( "==================== " + 说明 + " ====================" );
Console . WriteLine ( string . Join ( ',' , 队列 ) );
}
public class LEI妹妹 ( string 姓名 , double 体重 , double 身高 )
{
public string 姓名 { get; set; } = 姓名;
public double 体重 { get; set; } = 体重;
public double 身高 { get; set; } = 身高;
public override string ToString ( )
{
return $"{姓名},重 {体重} 公斤,身高 {身高} 米,BMI:{( 体重 / ( Math . Pow ( 身高 , 2 ) ) ):0.###}";
}
}备注
Max 和 Min 方法使用类或结构体等对 IComparable < T > 的实现来比较 队列 的元素或 比较选择器 产生的值。
可返回 null 值的重载中,如果 队列 为 Empty 或仅包含 null 值(无论有几个 null,可以是引用类型),此函数将返回 null。
如果你提供一个 比较选择器,将 队列 的成员投影到可比较类型(具体为 C# 中的 ( Nullable ) < T > 或 Visual Basic 中的 ( Nullable ) ( Of T ),关键是实现了 IComparable < T > 或 IComparable),就可以将此方法应用于任意类型的队列。第三个示例中,就把 Max 方法指定为 妹妹 的体重(不是对象默认的体重排序,这里你可以按姓名排序,返回值是 string);第四个示例直接描述了如何对比一堆没有实现 IComparable 和 IComparable < T > 接口的对象,通过计算得到一个可比较的对象即可。
在 Visual Basic 查询表达式语法中,Aggregate Into Max ( ) 子句会转换为对 Max 的调用。
MaxBy 和 MinBy
根据比较选择器产生的键值和可选的键比较器返回队列中的与 键值 相对第一个满足条件的值(MaxBy)和第一个不满足条件的值(MinBy)。
重载
| 重载 | 注解 |
|---|---|
| MaxBy < T源 , T键 > ( IEnumerable < T源 > , Func < T源 , T键 > ) | 根据比较选择器生成的键返回队列的第一个满足条件的值 |
| MinBy < T源 , T键 > ( IEnumerable < T源 > , Func < T源 , T键 > ) | 根据比较选择器(相反)生成的键返回队列的第一个不满足条件的值 |
| MaxBy < T源 , T键 > ( IEnumerable < T源 > , Func < T源 , T键 > , IComparer < T键 > ) | 根据比较选择器生成的键和键比较器返回队列的第一个满足条件的值 |
| MinBy < T源 , T键 > ( IEnumerable < T源 > , Func < T源 , T键 > , IComparer < T键 > ) | 根据比较选择器(相反)生成的键和键比较器返回队列的第一个不满足条件的值 |
public static T源? MaxBy <T源 , T键 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , T键 > 比较选择器 );
public static T源? MinBy <T源 , T键 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , T键 > 比较选择器 );
public static T源? MaxBy <T源 , T键 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , T键 > 比较选择器 , System . Collections . Generic . IComparer < T键 >? 键比较器 );
public static T源? MinBy <T源 , T键 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , T键 > 比较选择器 , System . Collections . Generic . IComparer < T键 >? 键比较器 );参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T源 | T | 源队列 的元素类型 |
| T键 | T | 比较选择器 生成的键的类型 |
| 比较选择器 | Func < T源 , T键 > | 提取 源队列 每个元素的键的函数 |
| 键比较器 | IComparer < T键 >? | 对 比较选择器 返回的键进行比较的比较器,null 或未指定则为 default |
返回值
| 类型 | 注解 |
|---|---|
| T源 | 队列中的极值元素(键值最大和最小(按键比较器的比较规则))的值 |
异常
| 异常 | 注解 |
|---|---|
| ArgumentException | 源队列 中存在未实现 IComparable 或 IComparable < T > 接口的元素 |
| ArgumentNullException | 源队列 或 比较选择器 为 null |
| InvalidOperationException | T源 为基元类型(C# 的值类型和 string 等),但 源队列 是 Empty |
示例
以下示例展示了 MaxBy 和 MinBy:
List < int > DLZhss =
[
1 , 19 , 36 , 58 , 24 , 44 , 15
];
FF显示队列 ( "原始队列:" , DLZhss );
int ZD20 = DLZhss . MaxBy ( x => x > 20 );
int ZX20 = DLZhss . MinBy ( x => x > 20 );
Console . WriteLine ( $"第一个大于 20 的值是:{ZD20},第一个小于 20 的值是:{ZX20}" );
static void FF显示队列 < T > ( string 说明 , IEnumerable < T > 队列 )
{
Console . WriteLine ( "==================== " + 说明 + " ====================" );
Console . WriteLine ( string . Join ( ',' , 队列 ) );
}备注
如果 源 的元素均为 null,根据源类型的不同,会出现两种可能的结果。如果 T源 为可空类型,此方法返回 null。如果 T源 为不可空值类型(如基元类型),则会引发 InvalidOperationException 异常。
如果源序列仅包含 null 值,此方法将返回 null。
OfType
按照指定类型筛选队列中的元素。 public static System . Collections . Generic . IEnumerable < T结果 > OfType < T结果 > ( this System . Collections . IEnumerable 源 );
参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T结果 | T | 返回队列的元素类型 |
| 源 | IEnumerable < T > | 源队列 |
返回值
| 类型 | 注解 |
|---|---|
| IEnumerable < T结果 > | 源 中符合 T结果 类型的元素组成的队列 |
异常
| 异常 | 注解 |
|---|---|
| ArgumentNullException | 源 为 null |
示例
以下示例创建了一个 朋友 队列,描述了你应该去找哪位朋友喝酒还是花钱(男的和女的):
List < LEI人 > PYs =
[
new LEI男人 { 姓名 = "张飞" },
new LEI女人 { 姓名 = "张月" },
new LEI男人 { 姓名 = "关羽" },
new LEI女人 { 姓名 = "关岭" },
];
FF显示队列 ( "酒队友:" , PYs . OfType < LEI男人 > ( ) );
FF显示队列 ( "狗仔队:" , PYs . OfType < LEI女人 > ( ) );
static void FF显示队列 < T > ( string 说明 , IEnumerable < T > 队列 )
{
Console . WriteLine ( "==================== " + 说明 + " ====================" );
Console . WriteLine ( string . Join ( ',' , 队列 ) );
}
public class LEI人
{
public string 姓名 { get; set; } = "";
}
public class LEI男人 : LEI人
{
public override string ToString ( )
{
return base . 姓名;
}
}
public class LEI女人 : LEI人
{
public override string ToString ( )
{
return base . 姓名;
}
}备注
此方法通过延迟执行来实现。其直接返回值是一个对象,该对象存储执行该操作所需的所有信息。只有当通过直接调用对象的 GetEnumerator 方法,或在 C# 中使用 foreach、在 Visual Basic 中使用 For Each 对该对象进行枚举时,此方法所表示的查询才会执行。
OfType 方法仅返回 源 中非 null 且与 T结果 类型兼容的元素。若希望在元素无法转换为 T结果 类型时引发异常,请使用 Cast < T结果> ( IEnumerable )。
此方法是为数不多可应用于具有非参数化类型(例如 ArrayList)的集合的标准查询运算符方法之一。这是因为 OfType 扩展了 IEnumerable 类型。OfType 不仅可应用于基于参数化 IEnumerable < T > 类型的集合,也可应用于基于非参数化 IEnumerable 类型的集合。
将 OfType 应用于实现 IEnumerable 的集合后,你就可以使用标准查询运算符对该集合进行查询。例如,为 OfType 指定 Object 类型参数,在 C# 中会返回 IEnumerable < Object > 类型的对象,在 Visual Basic 中则返回 IEnumerable ( Of Object ) 类型的对象,标准查询运算符可应用于该对象。
Order 和 OrderDescending
组合器 Order 按照某个规则分别梳理队列中的所有元素;OrderDescending 反序梳理。梳理的规则可以是 T 能处理的任意方式,例如 int 是否能整除 3,string 是否以“ab”起始等。仅当确保每个元素自成一个组,两个方法可以将队列的元素正向或反向排序,否则顺序仅限于组排序。
重载
| 重载 | 注解 |
|---|---|
| Order < T > ( IEnumerable < T > ) | 梳理队列中的所有元素(使用默认比较器) |
| Order < T > ( IEnumerable < T > , IComparer < T > ) | 梳理队列中的所有元素(使用指定比较器) |
| OrderDescending < T > ( IEnumerable < T > ) | 反序梳理队列中的所有元素(使用默认比较器) |
| OrderDescending < T > ( IEnumerable < T > , IComparer < T > ) | 反序梳理队列中的所有元素(使用指定比较器) |
public static System . Linq . IOrderedEnumerable < T > Order < T > ( this System . Collections . Generic . IEnumerable < T > 源 );
public static System . Linq . IOrderedEnumerable < T > Order < T > ( this System . Collections . Generic . IEnumerable < T > 源 , System . Collections . Generic . IComparer < T >? 比较器 );
public static System . Linq . IOrderedEnumerable < T > OrderDescending < T > ( this System . Collections . Generic . IEnumerable < T > 源 );
public static System . Linq . IOrderedEnumerable < T > OrderDescending < T > ( this System . Collections . Generic . IEnumerable < T > 源 , System . Collections . Generic . IComparer < T >? 比较器 );参数
| 参数 | 类型 | 注解 |
|---|---|---|
| 源 | IEnumerable < T > 源 | 欲分组组合的队列 |
| 键比较器 | IComparer < T >? | 对于队列中的元素的比较器,null 或未指定则为 T 的默认比较器 default |
返回值
| 类型 | 注解 |
|---|---|
| IOrderedEnumerable < T > | 一个包含已梳理好元素(正反组合序)的 IOrderedEnumerable < T > 队列 |
异常
| 异常 | 注解 |
|---|---|
| ArgumentNullException | 源 为 null |
示例
以下示例描述了一个 int 队列的组合(输出把偶数放在前面,奇数放在后面;或者反过来):
List < int > DLZhss = [ 3 , 1 , 6 , 4 , 1 , 5 ];
FF显示队列 ( "未梳理的队列:" , DLZhss );
var DLZhss整除2 = DLZhss . Order ( new LEI整除2比较器 ( ) ) ;
FF显示队列 ( "梳理好的正序队列:" , DLZhss整除2 );
var DLZhss整除2反序 = DLZhss . OrderDescending ( new LEI整除2比较器 ( ) );
FF显示队列 ( "梳理好的反序队列:" , DLZhss整除2反序 );
static void FF显示队列 < T > ( string 说明 , IEnumerable<T> 队列 )
{
Console . WriteLine ( "==================== " + 说明 + " ====================" );
Console . WriteLine ( string . Join ( ',' , 队列 ) );
}
public class LEI整除2比较器 : IComparer < int >
{
public int Compare ( int x , int y )
{
bool x是偶数 = FF整除2 ( x );
bool y是偶数 = FF整除2 ( y );
// 规则:偶数 排前面,奇数 排后面
return y是偶数 . CompareTo ( x是偶数 );
}
static bool FF整除2 ( int 整数 )
{
if ( 整数 % 2 == 0 ) return true;
return false;
}
}以下示例依然是“狐朋狗友”,但是按照默认的(LEI人 定义的)男女排序和自定义的姓名排序分别梳理该队列,从而形成了以男的组合起始女的组合结尾和姓关的组合起始姓张的组合结尾的两个不同的队列(由于默认比较器只关心男女,这不是排序,实际 Order 方法并没有改变元素的顺序,只是将符合条件的元素放在了一起;但姓名比较器实际完成了按姓名排序的功能;然后再反过来):
List < LEI人 > PYs =
[
new LEI男人 { 姓名 = "张飞" },
new LEI女人 { 姓名 = "张月" },
new LEI男人 { 姓名 = "关羽" },
new LEI女人 { 姓名 = "关岭" },
];
var Ren男女序列 = PYs . Order ( );
FF显示队列 ( "默认组合(男前女后):" , Ren男女序列 );
Ren男女序列 = PYs . OrderDescending ( );
FF显示队列 ( "默认组合(女前男后):" , Ren男女序列 );
var Ren姓名序列 = PYs . Order ( new LEI姓名比较器 ( ) );
FF显示队列 ( "姓名组合:" , Ren姓名序列 );
Ren姓名序列 = PYs . OrderDescending ( new LEI姓名比较器 ( ) );
FF显示队列 ( "姓名组合(反着的):" , Ren姓名序列 );
static void FF显示队列<T> ( string 说明 , IEnumerable<T> 队列 )
{
Console . WriteLine ( "==================== " + 说明 + " ====================" );
Console . WriteLine ( string . Join ( ',' , 队列 ) );
}
public class LEI人 : IComparable < LEI人 >
{
public string 姓名 { get; set; } = "";
public int CompareTo ( LEI人? other )
{
if ( other == null )
return 1;
bool Ber我是男人 = this is LEI男人;
bool Ber他是男人 = other is LEI男人;
return Ber他是男人 . CompareTo ( Ber我是男人 );
}
}
public class LEI男人 : LEI人
{
public override string ToString ( )
{
return base . 姓名;
}
}
public class LEI女人 : LEI人
{
public override string ToString ( )
{
return base . 姓名;
}
}
public class LEI姓名比较器 : IComparer<LEI人>
{
public int Compare ( LEI人? x , LEI人? y )
{
if ( x == null ) return 1;
if ( y == null ) return -1;
// 核心:按 姓名 字符串排序(字典序)
return x . 姓名 . CompareTo ( y . 姓名 );
}
}备注
方法通过延迟执行来实现。其直接返回值是一个“组合器”对象,该对象存储执行该操作所需的所有信息。只有当通过调用该对象的 GetEnumerator 方法对其进行枚举时,此方法所表示的查询才会执行。
方法通过使用默认或指定的 比较器 比较元素。
虽然叫“组合器”,根据比较器,Order 和 OrderDescending 实际可以完成队列整体元素的排序和反向排序。例如示例中按姓名分组的序列。当比较器的返回值不可能是多个元素时,Order 和 OrderDescending 实际完成了对所有元素的排序,只有当比较器返回值可能是多个元素时,实际是分组梳理,组之间是排序的,但组内部是按照元素在源队列中的顺序排列的。
“梳理”或“组合器”的理由是 Order 和 OrderDescending 的比较器的返回值键生成器不一定为每个元素生成一个不同的键,此时它只是分组所有元素,分组是有序的(它们都只是组排序器,GroupSorter),组内部不是(仅按照源队列出现的顺序),所以此时它不是排序元素(仅排序组);只有当比较器的返回值一定只是一个元素时,确实是对每个元素进行了排序(因为每个元素自成一个组)。此时它才能叫“元素排序器”。所以返回值的顺序不能作为元素的标准顺序,除非你确定每个组只包含一个元素。
OrderBy 和 OrderByDescending
按照 键生成器 生成的键升序或降序对队列的元素进行组合。
重载
| 重载 | 注解 |
|---|---|
| OrderBy < T源 , T键 > ( IEnumerable < T源 > , Func < T源 , T键 > ) | 使用默认比较器,根据键生成器的值对队列的元素进行升序组合 |
| OrderBy < T源 , T键 > ( IEnumerable < T源 > , Func < T源 , T键 > , IComparer < T > ) | 使用指定比较器,根据键生成器的值对队列的元素进行升序组合 |
| OrderByDescending < T源 , T键 > ( IEnumerable < T源 > , Func < T源 , T键 > ) | 使用默认比较器,根据键生成器的值对队列的元素进行降序组合 |
| OrderByDescending < T源 , T键 > ( IEnumerable < T源 > , Func < T源 , T键 > , IComparer < T > ) | 使用指定比较器,根据键生成器的值对队列的元素进行降序组合 |
public static System . Linq . IOrderedEnumerable < T源 > OrderBy < T源 , T键 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , T键 > 键生成器 );
public static System . Linq . IOrderedEnumerable < T源 > OrderBy < T源 , T键 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , T键 > 键生成器 , System . Collections . Generic . IComparer < T键 >? 键比较器 );
public static System . Linq . IOrderedEnumerable < T源 > OrderByDescending < T源 , T键 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , T键 > 键生成器 );
public static System . Linq . IOrderedEnumerable < T源 > OrderByDescending < T源 , T键 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , T键 > 键生成器 , System . Collections . Generic . IComparer < T键 >? 键比较器 );参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T源 | T | 源队列的元素类型 |
| T键 | T | 键生成器的返回值类型 |
| 源 | IEnumerable < T源 > | 欲分组组合的队列 |
| 键生成器 | Func < T源 , T键 > | 自元素中提取键的函数 |
| 键比较器 | IComparer < T键 >? | 比较键的比较器,null 或未指定则为 default |
返回值
| 类型 | 注解 |
|---|---|
| IOrderedEnumerable < T源 > | 一个按 键生成器 生成的键组合(正反序)好的队列 |
异常
| 异常 | 注解 |
|---|---|
| ArgumentNullException | 源 或 键生成器 为 null |
示例
以下示例排序一个 int 队列(先是使用了 键比较器(是否能整除 2),然后使用默认比较器):
List < int > DLZhss = [ 3 , 1 , 6 , 4 , 1 , 5 ];
FF显示队列 ( "未梳理的队列:" , DLZhss );
var DLZhss整除2 = DLZhss . OrderBy ( x => x , new LEI整除2比较器 ( ) ) ;
FF显示队列 ( "具有整除 2 键比较器的正序队列:" , DLZhss整除2 );
var DLZhss整除2反序 = DLZhss . OrderByDescending ( x => x , new LEI整除2比较器 ( ) );
FF显示队列 ( "具有整除 2 键比较器的反序队列:" , DLZhss整除2反序 );
var DLZhss正序 = DLZhss . OrderBy ( x=> x );
FF显示队列 ( "没有键比较器的正序:" , DLZhss正序 );
var DLZhss反序 = DLZhss . OrderByDescending ( x=> x );
FF显示队列 ( "没有键比较器的反序:" , DLZhss反序 );
static void FF显示队列<T> ( string 说明 , IEnumerable < T > 队列 )
{
Console . WriteLine ( "==================== " + 说明 + " ====================" );
Console . WriteLine ( string . Join ( ',' , 队列 ) );
}以下依然是“狐朋狗友”。按照其姓名排序:
List < LEI人 > PYs =
[
new LEI男人 { 姓名 = "张飞" },
new LEI女人 { 姓名 = "张月" },
new LEI男人 { 姓名 = "关羽" },
new LEI女人 { 姓名 = "关岭" },
];
var Ren姓名序列 = PYs . OrderBy ( r => r . 姓名 );
FF显示队列 ( "默认序列(关前张后):" , Ren姓名序列 );
Ren姓名序列 = PYs . OrderByDescending ( r => r . 姓名 );
FF显示队列 ( "默认序列(张前关后):" , Ren姓名序列 );
static void FF显示队列<T> ( string 说明 , IEnumerable<T> 队列 )
{
Console . WriteLine ( "==================== " + 说明 + " ====================" );
Console . WriteLine ( string . Join ( ',' , 队列 ) );
}备注
此方法通过延迟执行来实现。其直接返回值是一个“组合器”对象,该对象存储执行该操作所需的所有信息。只有当通过直接调用对象的 GetEnumerator 方法,或在 C# 中使用 foreach、在 Visual Basic 中使用 For Each 对该对象进行枚举时,此方法所表示的查询才会执行。
要根据元素本身的值对队列进行组合,请为 键生成器 指定恒等函数(C# 中的 x => x 或 Visual Basic 中的 Function ( x ) x)。
定义了两种方法来扩展作为此方法返回类型的 IOrderedEnumerable < T源 >。这两种方法分别是 ThenBy 和 ThenByDescending,它们使你能够指定额外的排序条件来对序列进行排序。ThenBy 和 ThenByDescending 同样会返回一个 IOrderedEnumerable < T源 >,这意味着可以连续调用任意次数的 ThenBy 或 ThenByDescending。
注意:由于 IOrderedEnumerable < T源 > 继承自 IEnumerable < T >,你可以在调用 OrderBy、OrderByDescending、ThenBy 或 ThenByDescending 的结果上调用 OrderBy 或 OrderByDescending。这样做会引入一种新的主组合方式,该方式会忽略之前已建立的排序规则。
如果 键比较器 为 null,则使用默认比较器 Default 来比较键。
此方法执行稳定排序;也就是说,若两个元素的键相等,则元素的顺序会保持不变。相比之下,不稳定排序不会保留键相同的元素的顺序。
虽然叫“组合器”,根据比较器,OrderBy 和 OrderByDescending 实际可以完成队列的整体元素的排序和反向排序。例如示例中按姓名分组的序列。当比较器的返回值不可能是多个元素时,Order 和 OrderDescending 实际完成了对所有元素的排序,只有当比较器返回值可能是多个元素时,实际是分组梳理,组之间是排序的,但组内部是按照元素在源队列中的顺序排列的。
“梳理”或“组合器”的理由是 OrderBy 和 OrderByDescending 的键生成器不一定为每个元素生成一个不同的键,此时它只是分组所有元素,分组是有序的(它们都只是组排序器,GroupSorter),组内部不是(仅按照源队列出现的顺序),所以此时它不是排序元素(仅排序组);只有当比较器的返回值一定只是一个元素时,确实是对每个元素进行了排序(因为每个元素自成一个组)。此时它才能叫“元素排序器”。所以返回值的顺序不能作为元素的标准顺序,除非你确定每个组只包含一个元素。
在查询表达式语法中,orderby(C#)或 Order By(Visual Basic)子句会转换为对 OrderBy 的调用。
Prepend
返回一个队列,由指定值起始,源队列的元素随后组成。 public static System . Collections . Generic . IEnumerable < T源 > Prepend < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , T源 起始 );
参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T源 | T | 源队列的元素类型 |
| 源 | IEnumerable < T源 > | 结果队列的其余元素组成的队列 |
| 起始 | T源 | 结果队列的起始元素 |
返回值
| 类型 | 注解 |
|---|---|
| IEnumerable < T源 > | 一个由 起始 后跟 源 的所有元素组成的新队列 |
异常
| 异常 | 注解 |
|---|---|
| ArgumentNullException | 源 为 null |
示例
以下示例展示了 Prepend 的用途:
PYs . Prepend ( new LEI女人 { 姓名 = "刘晓倩" } ); // 此语句无效,因为没有赋值
FF显示队列 ( "无效的 Prepend:" , PYs );
FF显示队列 ( "有效的 Prepend:" , PYs . Prepend ( new LEI女人 { 姓名 = "刘晓倩" } ) );
List < LEI人 > LiuRen = [ .. PYs . Prepend ( new LEI女人 { 姓名 = "刘晓倩" } ) ];
FF显示队列 ( "另一个有效的 Prepend:" , LiuRen );
static void FF显示队列 < T > ( string 说明 , IEnumerable < T > 队列 )
{
Console . WriteLine ( "==================== " + 说明 + " ====================" );
Console . WriteLine ( string . Join ( ',' , 队列 ) );
}Range
生成指定范围内的整数队列。 public static System . Collections . Generic . IEnumerable < int > Range ( int 起始 , int 元素数 );
参数
| 参数 | 类型 | 注解 |
|---|---|---|
| 起始 | int | 范围的起始值 |
| 元素数 | int | 范围的元素数 |
返回值
| 类型 | 注解 |
|---|---|
| IEnumerable < Int > | 或 Visual Basic 中的 IEnumerable ( Of Int32 ),一系列连续整数组成的队列 |
异常
| 异常 | 注解 |
|---|---|
| ArgumentOutOfRangeException | 元素数 小于 0 起始 + 元素数 - 1 大于 int . MaxValue |
示例
以下示例分别创建了一个连续整数队列和该队列的变形队列(元素本身的元素次方):
IEnumerable < int > DL连续整数 = Enumerable . Range ( 3 , 7 );
FF显示队列 ( "3 起始,7 个元素的队列:" , DL连续整数 );
DL连续整数 = Enumerable . Range ( 3 , 7 ) . Select ( x => ( int ) Math . Pow ( x , x ) );
FF显示队列 ( "3 起始,7 个元素的队列(元素本身的元素次方):" , DL连续整数 );
static void FF显示队列 < T > ( string 说明 , IEnumerable < T > 队列 )
{
Console . WriteLine ( "==================== " + 说明 + " ====================" );
Console . WriteLine ( string . Join ( ',' , 队列 ) );
}备注
此方法通过延迟执行来实现。其直接返回值是一个对象,该对象存储执行操作所需的所有信息。只有当通过直接调用对象的 GetEnumerator 方法,或在 C# 中使用 foreach、在 Visual Basic 中使用 For Each 对该对象进行枚举时,此方法所表示的查询才会执行。
Repeat
生成一个重复元素的队列。 public static System . Collections . Generic . IEnumerable < T结果 > Repeat < T结果 > ( T结果 元素 , int 元素数 );
参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T结果 | T | 输出队列的元素类型 |
| 元素 | T结果 | 输出队列中的重复元素 |
| 元素数 | int | 输出队列的 Count |
返回值
| 类型 | 注解 |
|---|---|
| IEnumerable < T结果 > | 一个由 元素数 个 元素 组成的队列 |
异常
| 异常 | 注解 |
|---|---|
| ArgumentOutOfRangeException | 元素数 小于 0 |
示例
以下示例展示了某些烦恼场面:
IEnumerable < int > DLZhss连续15 = Enumerable . Repeat ( 15 , 5 );
FF显示队列 ( "连续 5 个 15:" , DLZhss连续15 );
IEnumerable < string > DLZfcs连续滚 = Enumerable . Repeat ( "滚" , 5 );
FF显示队列 ( "连续 5 个 滚:" , DLZfcs连续滚 );
static void FF显示队列<T> ( string 说明 , IEnumerable<T> 队列 )
{
Console . WriteLine ( "==================== " + 说明 + " ====================" );
Console . WriteLine ( string . Join ( ',' , 队列 ) );
}备注
此方法通过延迟执行来实现。其直接返回值是一个对象,该对象存储执行该操作所需的所有信息。只有当通过直接调用对象的 GetEnumerator 方法,或在 C# 中使用 foreach、在 Visual Basic 中使用 For Each 对该对象进行枚举时,此方法所表示的查询才会执行。
Reverse
反转队列内元素的顺序。
public static System . Collections . Generic . IEnumerable < T源 > Reverse < T源 > ( this T源 [ ] 源 );
public static System . Collections . Generic . IEnumerable < T源 > Reverse < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 );参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T源 | T | 源队列的元素类型 |
| 源 | T源 [ ] IEnumerable < T源 > | 欲反转的源队列 |
返回值
| 类型 | 注解 |
|---|---|
| IEnumerable < T源 > | 一个将 源队列 元素次序反转的队列 |
异常
| 异常 | 注解 |
|---|---|
| ArgumentNullException | 当 源 不是一个 T源 [ ],且 源 是 null |
示例
以下示例展示了一个 int 队列的反转:
List < int > DLZhss = [ 3 , 1 , 6 , 4 , 1 , 5 ];
IEnumerable < int > DL反着的 = Enumerable . Reverse ( DLZhss );
FF显示队列 ( "正着的:" , DLZhss );
FF显示队列 ( "反着的:" , DL反着的 );
static void FF显示队列 < T > ( string 说明 , IEnumerable < T > 队列 )
{
Console . WriteLine ( "==================== " + 说明 + " ====================" );
Console . WriteLine ( string . Join ( ',' , 队列 ) );
}备注
此方法通过延迟执行来实现。其直接返回值是一个对象,该对象存储执行该操作所需的所有信息。只有当通过直接调用对象的 GetEnumerator 方法,或在 C# 中使用 foreach、在 Visual Basic 中使用 For Each 对该对象进行枚举时,此方法所表示的查询才会执行。
与 OrderBy 不同,此排序方法在确定顺序时不考虑实际值本身。相反,它仅按基础源生成元素的逆序返回这些元素。
Select(即 AllOutor)
将源队列中的每个元素,按照方法指定的计算规则生成新的队列。计算规则可以是元素的任何成员以及符合其类型的计算的组合,或者元素本身。AllOutor(本意是,这个方法和选择的意思无关)意即 Select 实为对元素改造(可能没改)后生成新的队列,顺序不变,但每个元素都经过了计算规则(一个函数)的改造。
重载
| 重载 | 注解 |
|---|---|
| Select < T源 , T结果 > ( IEnumerable < T源 > , Func < T源 , T结果 > ) | 根据计算规则改造所有元素 |
| Select < T源 , T结果 > ( IEnumerable < T源 > , Func < T源 , int , T结果 > ) | 根据计算规则改造所有元素(附带索引) |
public static System . Collections . Generic . IEnumerable < T结果 > Select < T源 , T结果 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , T结果 > 改造规则 );
public static System . Collections . Generic . IEnumerable < T结果 > Select < T源 , T结果 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , int 索引 , T结果 > 改造规则 );参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T结果 | T | 结果队列的元素类型 |
| T源 | T | 源队列的元素类型 |
| 源 | IEnumerable < T源 > | 欲改造的源队列 |
| 改造规则 | Func < T源 , T结果 > Func < T源 , int 索引 , T结果 > | 针对源队列每个元素的改造函数,可以附带索引 |
| 索引 | int | 返回队列的元素排序(与源队列相一致) |
返回值
| 类型 | 注解 |
|---|---|
| IEnumerable < T结果 > | 其每个元素都是 源 的每个元素被 改造规则 改造的结果 |
异常
| 异常 | 注解 |
|---|---|
| ArgumentNullException | 源 或 改造规则 为 null |
示例
以下示例通过 Repeat 创建了一个 5 个 string 元素的队列,每个元素均为“0123456789”,并通过索引确定每个元素的改造规则:
List < string > zfcs = [ .. Enumerable . Repeat ( "0123456789" , 5 ) ];
var chx = zfcs . Select ( ( z , suoyin ) => new { suoyin , zfc = z . Substring ( suoyin , suoyin + 1 ) } );
foreach ( var z in chx )
{
Console.WriteLine ( z );
}以下示例队列中的 10 个 int 元素由随机生成 -5 ~ 5 之间的整数,改造规则是当 元素 为零,就创建 0,否则创建其相反数:
Random sjs = new ( );
List < int > zhss = [ ];
for ( int i = 0 ; i <= 9 ; i++ )
{
zhss . Add ( sjs . Next ( -5 , 6 ) );
}
FF显示队列 ( "原始队列:" , zhss );
var zhss相反 = zhss . Select ( z => ( z == 0 ? z : -z ) );
FF显示队列 ( "相反数的队列:" , zhss相反 );
static void FF显示队列<T> ( string 说明 , IEnumerable<T> 队列 )
{
Console . WriteLine ( "==================== " + 说明 + " ====================" );
Console . WriteLine ( string . Join ( ',' , 队列 ) );
}以下示例展示了某些比赛的要求(比赛人数多于 3 人,平均年龄小于 60 岁,免得心梗啥的):
Console . OutputEncoding = Encoding . UTF8;
List < LEI参赛 > BS1 = [ new LEI参赛 { 姓名 = "张飞" , 年龄 = 46 } , new LEI参赛 { 姓名 = "张飞妹" , 年龄 = 40 } ];
List < LEI参赛 > BS2 = [ new LEI参赛 { 姓名 = "龙飞虎" , 年龄 = 86 } , new LEI参赛 { 姓名 = "龙飞娘" , 年龄 = 84 } , new LEI参赛 { 姓名 = "龙飞妹" , 年龄 = 58 } ];
List < LEI参赛 > BS3 = [ new LEI参赛 { 姓名 = "陈不死" , 年龄 = 46 } , new LEI参赛 { 姓名 = "周不败" , 年龄 = 50 } , new LEI参赛 { 姓名 = "周小弟" , 年龄 = 21 } ];
List < List < LEI参赛 > > CSDW = [ BS1 , BS2 , BS3 ];
IEnumerable < string > chx = CSDW . Select ( ( d , suoyin ) =>
d . Count < 3
? $"队伍 {suoyin + 1} 人数太少了"
: d . Average ( n => n . 年龄 ) <= 60
? $"队伍 {suoyin + 1} 人数 {d . Count} 和平均年龄 {d . Average ( n => n . 年龄 )} 均合适"
: $"队伍 {suoyin + 1} 平均年龄太大了,小心死场上😄"
);
FF显示队列 ( "比赛队伍列表:" , chx );
static void FF显示队列<T> ( string 说明 , IEnumerable<T> 队列 )
{
Console . WriteLine ( "==================== " + 说明 + " ====================" );
Console . WriteLine ( string . Join ( ',' , 队列 ) );
}备注
此方法通过延迟执行来实现。其直接返回值是一个对象,该对象存储执行该操作所需的所有信息。只有当通过直接调用对象的 GetEnumerator 方法,或在 C# 中使用 foreach、在 Visual Basic 中使用 For Each 对该对象进行枚举时,此方法所表示的查询才会执行。
具有 索引 参数的 改造规则 的第一个参数表示要处理的元素。第二个参数表示该元素在源序列中的从零开始的索引。例如,如果元素处于已知顺序中,且你想对特定索引的元素执行某些操作,这会很有用。当你想要获取一个或多个元素的索引时,该参数同样适用。
由于每个元素都被 改造规则 处理过,其结果元素不一定是想得到的(你可能只想得到源队列中的“理想”元素)。此时应使用 . ToArray 或 . ToList 方法生成其数组或列表版本(具有 Remove 等方法),按照某个方式移除队列中的部分元素,例如其值为 null、0(值类型)、Empty 等:
List < int > DLX = zhss相反 . ToList ( );
DLX . RemoveAll ( x => x == 0 );此投影方法要求 改造规则 为 源队列 中的每个值生成一个值。如果 改造规则 返回的值本身是一个集合,则由使用者手动遍历这些子序列。在这种情况下,最好让查询返回一个合并后的单值序列。要实现这一点,请使用 SelectMany 方法而非 Select 方法。尽管 SelectMany 的工作原理与 Select 相似,但二者的区别在于 改造规则 会返回一个集合,该集合随后会被 SelectMany 展开后再返回。
在查询表达式语法中,select(C#)或 Select(Visual Basic)子句会转换为对 Select 方法的调用。
SelectMany(AllAnyOutor)
将源队列中的每个元素(必须是个队列),按照方法指定的计算规则计算其每个元素,并生成新的队列(相当于合并源队列中的每个元素)。计算规则可以是每个队列的每个元素的任何成员以及符合其类型的计算的组合,或者元素本身。AllAnyOutor(我的本意是,这个方法和选择的意思无关)意即 SelectMany 实为对队列中每个元素改造(可能没改)后生成新的队列,顺序不变,但每个元素都经过了计算规则(一个函数)的改造。
重载
| 重载 | 注解 |
|---|---|
| SelectMany < T源 , T结果 > ( IEnumerable < T源 > , Func < T源 , IEnumerable < T结果 > > ) | 将 源 的子队列中的每个元素改组并生成元素类型为 T结果 的一个整体队列(可以选择性地筛选元素) |
| SelectMany < T源 , T结果 > ( IEnumerable < T源 > , Func < T源 , Int32 , IEnumerable < T结果 > > ) | 将 源 的子队列中的每个元素改组并生成元素类型为 T结果 的一个整体队列(可以选择性地筛选元素)。索引实为 源 的元素索引(子队列的索引) |
| SelectMany < T源 , T间接 , T结果 > ( IEnumerable < T源 > , Func < T源 , IEnumerable < T间接 > > , Func < T源 , T间接 , T结果 > ) | 将 源 的子队列中的每个元素改组并生成元素类型为 T间接 的一个整体队列(可以选择性地筛选元素)并按照 结果表达器 生成 T结果 类型的队列 |
| SelectMany < T源 , T间接 , T结果 > ( IEnumerable < T源 > , Func < T源 , Int32 , IEnumerable < T间接 > > , Func < T源 , T间接 , T结果 > ) | 将 源 的子队列中的每个元素改组并生成元素类型为 T间接 的一个整体队列(可以选择性地筛选元素)并按照 结果表达器 生成 T结果 类型的队列。索引实为 源 的元素索引(子队列的索引) |
public static System . Collections . Generic . IEnumerable < T结果 > SelectMany < T源 , T结果 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , System . Collections . Generic . IEnumerable < T结果 > > 结果表达器 );
public static System . Collections . Generic . IEnumerable < T结果 > SelectMany < T源 , T结果 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , int 索引 , System . Collections . Generic . IEnumerable < T结果 > > 结果表达器 );
public static System . Collections . Generic . IEnumerable < T结果 > SelectMany < T源 , T间接 , T结果 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , System . Collections . Generic . IEnumerable < T间接 > > 间接选择器 , Func < T源 , T间接 , T结果 > 结果表达器 );
public static System . Collections . Generic . IEnumerable < T结果 > SelectMany < T源 , T间接 , T结果 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , int 索引 , System . Collections . Generic . IEnumerable < T间接 > > 间接选择器 , Func < T源 , T间接 , T结果 > 结果表达器 );参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T结果 | T | 结果队列的元素类型 |
| T源 | T | 源队列的元素类型 |
| 源 | IEnumerable < T源 > | 欲改组的源队列 |
| 结果表达器 | Func < T源 , IEnumerable < T结果 > > Func < T源 , T间接 , T结果 > | 将 源队列 或 间接队列 的每个元素改组为 T结果 类型的函数 |
| 索引 | int | 返回 源 的元素(子队列)索引(与源队列相一致,但源队列不一定是可索引的) |
| 间接选择器 | Func < T源 , IEnumerable < T间接 > > Func < T源 , int , IEnumerable < T间接 > > | 一个对 源 的元素初步处理的函数(可以用 Where 等方法筛选元素) |
返回值
| 类型 | 注解 |
|---|---|
| IEnumerable < T结果 > | 一个以 T结果 为元素类型的可枚举对象,其元素由 源 的每个元素或 间接选择器(可能被筛选)生成的队列的每个元素按 结果表达器 函数生成 |
异常
| 异常 | 注解 |
|---|---|
| ArgumentNullException | 源 或 间接选择器 或 结果表达器 为 null |
示例
以下示例创建了两个 int 队列,合并为一个 List < List < int > >,然后再使用无索引和带索引的 SelectMany 求它们的元素的相反数:
Random sjs = new ( );
List < int > zhss1 = [ ];
List < int > zhss2 = [ ];
for ( int i = 0 ; i <= 9 ; i++ )
{
zhss1 . Add ( sjs . Next ( -5 , 6 ) );
zhss2 . Add ( sjs . Next ( -5 , 6 ) );
}
List < List < int > > Zhss = [ zhss1 , zhss2 ];
FF显示队列 ( "原始队列 1:" , zhss1 );
FF显示队列 ( "原始队列 2:" , zhss2 );
var zhss相反 = Zhss . SelectMany ( zu => zu . Select ( z => z == 0 ? "零" : ( -z ) . ToString ( ) ) );
FF显示队列 ( "相反数的队列:" , zhss相反 );
var zhss索引相反 = Zhss . SelectMany ( ( zu , suoyin ) => zu . Select ( z => $"队列 {suoyin + 1}:{( z == 0 ? "零" : (-z).ToString ( ) )}"));
FF显示队列 ( "带索引的相反数的队列:" , zhss索引相反 );以下示例继承自上述示例,但它只是返回了两个队列中的正数: var zhss正数 = Zhss . SelectMany ( zu => zu . Where ( z => z > 0 ) , ( zu , zheng ) => $"正数:{zheng}" );
备注
此方法通过延迟执行来实现。其直接返回值是一个对象,该对象包含执行该操作所需的所有信息。只有当通过直接调用对象的 GetEnumerator 方法,或在 C# 中使用 foreach、在 Visual Basic 中使用 For Each 对该对象进行枚举时,此方法所表示的查询才会执行。
SelectMany 方法会枚举 源 队列,借助 间接选择器 和/或 结果表达器 将每个元素改组为一个IEnumerable < T >,随后枚举并生成每个此类 IEnumerable < T > 对象的元素。也就是说,对于 源 的每个元素,都会调用 间接选择器 或 结果表达器 并返回一个值队列。随后会将这个二维队列(队列的队列)展平为一维的 IEnumerable < T > 并返回。例如,若查询使用 SelectMany 来获取数据库中每个客户的订单(组 类型),在 C# 中结果类型为 IEnumerable < 组 >,在 Visual Basic 中则为 IEnumerable ( Of 组 )。反之,若查询使用 Select 来获取订单,订单的集合集合不会被合并,在 C# 中结果类型为 IEnumerable < List < 组 > >,在 Visual Basic 中则为 IEnumerable ( Of List ( Of 组 ) )。
在查询表达式语法中,初始的 from 子句(C#)或 From 子句(Visual Basic)之后的每一个子句,都会转换为对 SelectMany 方法的调用。可以通过 Sum、Average 等方法,描述其返回值(一个队列)的某些状态,例如总和、平均值等。
Sequence
生成一个值类型的等差数列,以 起始 起始,直到下一个值大于(公差 为正值)或小于(公差 为负值)终值为止。 public static System . Collections . Generic . IEnumerable < T > Sequence < T > ( T 起始 , T 终值 , T 公差 ) where T : System . Numerics . INumber < T >;
参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T | T | 等差数列的值类型 |
| 起始 | T | 等差数列的起始值(始终包含) |
| 终值 | T | 等差数列的终值(可能不存在于数列中) |
| 公差 | T | 等差数列的公差 |
返回值
| 类型 | 注解 |
|---|---|
| IEnumerable < T > | 一个等差数列 |
异常
| 异常 | 注解 |
|---|---|
| ArgumentNullException | 起始 或 终值 或 公差 为 null |
| ArgumentOutOfRangeException | 起始 或 终值 或 公差 为 NaN 终值大于起始,但公差小于 0 终值小于起始,但公差大于 0 终值不等于起始,但公差为 0 |
示例
以下示例分别使用 ±3.14 创建两个等差数列(decimal):
IEnumerable < decimal > SJDs正 = Enumerable . Sequence ( 0m , 20m , 3.14m );
IEnumerable < decimal > SJDs负 = Enumerable . Sequence ( 0m , -20m , -3.14m );备注
与 Range 的最大区别就在于其公差可以是符合条件(起始 和 终值)的任意值。
终值 可能包含在生成的数列中,仅限于下一个值正好是 终值 时。当使用 float 或 double 类型时,些许的误差可能导致数列的终值与预期不符,因为计算结果可能大于或小于预期的终值。例如,预期的终值是 15,公差是 0.1(二进制无限循环小数),实际的终值可能是 14.99999999999998,因为它的下一个值可能是 15.000000000000002,已经被认为大于 15。如果使用 float 或 double 类型,不要相信等差数列的终值,如果公差是具有小数位数的数值,应使用 decimal 类型,确保得到预期的终值。
SequenceEqual
根据两个队列的长度,以及每个元素(根据默认比较器或指定比较器)是否相等,返回两个队列是否相等。
重载
| 重载 | 注解 |
|---|---|
| SequenceEqual < T源 > ( IEnumerable < T源 > , IEnumerable < T源 > ) | 使用默认比较器判断两个队列是否相等 |
| SequenceEqual < T源 > ( IEnumerable < T源 > , IEnumerable < T源 > , IEqualityComparer < T源 > ) | 使用指定比较器判断两个队列是否相等 |
public static bool SequenceEqual < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 首 , System . Collections . Generic . IEnumerable < T源 > 次 );
public static bool SequenceEqual < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 首 , System . Collections . Generic . IEnumerable < T源 > 次 , IEqualityComparer < T源 > 比较器 );参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T源 | T | 欲比较的两个队列的元素类型 |
| 首 次 | IEnumerable < T源 > | 欲比较的两个队列 |
| 比较器 | IEqualityComparer < T源 > | 对两个队列的元素的比较器 |
返回值
| 类型 | 注解 |
|---|---|
| bool | 若 首、次 长度相等,且每个相应元素(按比较器)也相等,返回 true;否则返回 false |
异常
| 异常 | 注解 |
|---|---|
| ArgumentNullException | 首 和/或 次 为 null |
示例
下面的示例 首 为一个 3 元素的 int 队列,分别与 3 个 int 队列的比较结果:
IEnumerable < int > shou = [ 1 , 2 , 3 ];
IEnumerable < int > ci1 = [ 1 , 2 , 3 ];
bool bj1 = shou . SequenceEqual ( ci1 );
Console . WriteLine ( $"这两个真相等,所以:{bj1}" );
IEnumerable < int > ci2 = [ 1 , 2 , 3 , 4 ];
bool bj2 = shou . SequenceEqual ( ci2 );
Console . WriteLine ( $"这两个长度不等,所以:{bj2}" );
IEnumerable < int > ci3 = [ 1 , 2 , 1 ];
bool bj3 = shou . SequenceEqual ( ci3 );
Console . WriteLine ( $"这两个元素不等,所以:{bj3}" );以下示例展示了使用 比较器 来比较自定义类的对象,该类是个图形,当图形的形状和大小均相同,即视为两个对象相同:
LEI图形 [ ] shou =
[
new LEI图形 { 形状 = "圆" , 大小 = 3.14m },
new LEI图形 { 形状 = "正方形" , 大小 = 10m },
];
LEI图形 [ ] ci1 =
[
new LEI图形 { 形状 = "圆" , 大小 = 3.14m },
new LEI图形 { 形状 = "正方形" , 大小 = 10m },
];
LEI图形 [ ] ci2 =
[
new LEI图形 { 形状 = "圆" , 大小 = 3.14m },
new LEI图形 { 形状 = "长方形" , 大小 = 10m },
];
bool bj1 = Enumerable . SequenceEqual ( shou , ci1 , new LEI图形比较器 ( ) ); // 此处若未指定比较器,由于对象是引用类型,虽然形状和大小都相等,但被认为是不同的对象,不相等
FF显示队列 ( "首:" , shou );
FF显示队列 ( "次 1:" , ci1 );
Console . WriteLine ( $"它俩相等吗:{bj1}" );
bool bj2 = Enumerable . SequenceEqual ( shou , ci2 , new LEI图形比较器 ( ) );
FF显示队列 ( "首:" , shou );
FF显示队列 ( "次 2:" , ci2 );
Console . WriteLine ( $"它俩相等吗:{bj2}" );
public class LEI图形
{
public string? 形状 { get; set; }
public decimal 大小 { get; set; }
public override string ToString ( )
{
return $"{形状}:{大小}";
}
}
public class LEI图形比较器 : IEqualityComparer < LEI图形 >
{
// 如果两个图形的形状和大小都一致,即被认为是相同的
public bool Equals ( LEI图形? x , LEI图形? y )
{
// 首先检查两个对象是否引用相同的数据
if ( object . ReferenceEquals ( x , y ) ) return true;
// 任意一个值为 null,返回 false
if ( x is null || y is null )
return false;
// 通过对图形的形状和大小的检查
return x . 形状 == y . 形状 && x . 大小 == y . 大小;
}
public int GetHashCode ( [DisallowNull] LEI图形 obj )
{
// null 返回 0
if ( obj is null ) return 0;
// 当形状不是 null,获取形状的 HashCode
int TX哈希 = obj . 形状 == null ? 0 : obj . 形状 . GetHashCode ( );
// 获取大小的 HashCode
int TX大小哈希 = obj . 大小 . GetHashCode ( );
// 计算整个图形的 HashCode
return TX哈希 ^ TX大小哈希;
}
}注解
该方法并行枚举 首、次 两个队列,并使用指定的 比较器 比较相应的元素。如果比较器是 null 或未指定,则使用默认相等比较器 Default 来比较元素。若要比较自定义数据类型,需要重写 Equals 和 GetHashCode 方法,并选择性地在自定义类型中实现 IEquatable < T > 泛型接口。
方法中互换 首、次 两个参数的位置对于结果没有影响。首 次 之间的元素是否相等,仅和比较器有关。
Shuffle
将队列中的元素的次序打乱(随机的)。 public static System . Collections . Generic . IEnumerable < T源 > Shuffle < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 );
参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T源 | T | 源队列的元素类型 |
| 源 | IEnumerable < T源 > | 欲打乱次序的队列 |
返回值
| 类型 | 注解 |
|---|---|
| IEnumerable < T源 > | 被打乱次序的源队列(包含所有 源 中的元素) |
示例
以下示例展示了 Shuffle:
List < int > DLZhss = [ 3 , 1 , 6 , 4 , 1 , 5 ];
FF显示队列 ( "没被打乱了的:" , DLZhss );
IEnumerable < int > zhss打乱的 = DLZhss . Shuffle ( );
FF显示队列 ( "打乱了的:" , zhss打乱的 );以下示例展示了 Shuffle 可能的同一时间产生同一结果的场景:
List < int > DLZhss = [ 3 , 1 , 6 , 4 , 1 , 5 ];
FF显示队列 ( "没被打乱了的:" , DLZhss );
IEnumerable < int > zhss打乱的1 = DLZhss . Shuffle ( );
IEnumerable < int > zhss打乱的2 = DLZhss . Shuffle ( );
FF显示队列 ( "打乱了的 1:" , zhss打乱的1 );
FF显示队列 ( "打乱了的 2:" , zhss打乱的2 );备注
使用非加密安全的随机数生成器执行随机化操作。类似示例 1,每次运行 Shuffle 的结果都是不一样的。
使用费舍尔-耶茨(Fisher-Yates)洗牌算法,保证每个排列出现的概率相等。当队列中的元素足够多,几乎不可能出现两次运行结果相同的情况,例如示例 1。随机种子来自于当前时间,所以同一时间创建 n 个 Shuffle 实例可能是相同的,例如示例 2。
Single 和 SingleOrDefault
Single 返回单元素队列中的唯一元素,或者多元素队列中符合条件的唯一元素,队列必须是单元素队列,或者有且仅有一个符合条件的元素。SingleOrDefault 与 Single 的唯一区别,是允许队列 Count 为 0(即没有元素),或者没有符合条件的元素,此时它返回 源队列 元素类型的默认值。
重载
| 重载 | 注解 |
|---|---|
| Single < T源 > ( IEnumerable < T源 > ) | 返回队列中的唯一元素(队列必须是单元素队列) |
| Single < T源 > ( IEnumerable < T源 > , Func < T源 , bool > ) | 返回队列中的符合条件的唯一元素(队列可以有 n 个元素,但有且仅有一个是符合条件的) |
| SingleOrDefault < T源 > ( IEnumerable < T源 > ) | 返回队列中的唯一元素或 T源 的默认值(队列必须是单元素队列或者 Empty) |
| SingleOrDefault < T源 > ( IEnumerable < T源 > , T源 ) | 返回队列中的唯一元素或指定的默认值(队列必须是单元素队列或者 Empty) |
| SingleOrDefault < T源 > ( IEnumerable < T源 > , Func < T源 , bool > ) | 返回队列中的符合条件的唯一元素或默认值(队列可以有 n 个元素,且仅有一个是符合条件的或没有,或者队列是 Empty) |
| SingleOrDefault < T源 > ( IEnumerable < T源 > , Func < T源 , bool > , T源 ) | 返回队列中的符合条件的唯一元素或指定默认值(队列可以有 n 个元素,且仅有一个是符合条件的或没有,或者队列是 Empty) |
public static T源 Single < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 );
public static T源 Single < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , bool > 条件委托 );
public static T源? SingleOrDefault < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 );
public static T源? SingleOrDefault < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , T源 默认值 );
public static T源? SingleOrDefault < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , bool > 条件委托 );
public static T源? SingleOrDefault < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , bool > 条件委托 , T源 默认值 );参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T源 | T | 源队列的元素类型 |
| 源 | IEnumerable < T源 > | 欲取出单个元素的队列 |
| 条件委托 | Func < T源 , bool > | 当 源 非单元素队列,筛选元素的条件函数 |
| 默认值 | T源 | 当没有符合条件的元素,或 源 为 Empty(仅限 SingleOrDefault)时的返回值 |
返回值
| 方法 | 类型 | 注解 |
|---|---|---|
| Single | T源 | 队列中的唯一(符合条件的)元素 |
| SingleOrDefault | T源? | 队列中的唯一(符合条件的)元素;若不存在,或队列为 Empty,则为 T源 的默认值或 默认值 参数指定值 |
异常
| 方法 | 异常 | 注解 |
|---|---|---|
| Single SingleOrDefault | ArgumentNullException | 源 或 条件委托 为 null |
| Single SingleOrDefault | InvalidOperationException | 使用无 条件委托 版本的重载时,源 为多元素队列。仅 SingleOrDefault 允许 源 为 Empty |
| Single | InvalidOperationException | 源 为 Empty 不是仅有 1 个元素符合条件委托(有 条件委托 版本) |
| SingleOrDefault | InvalidOperationException | 多于 1 个元素符合条件委托(有 条件委托 版本) |
示例
以下示例描述了 Single 的单元素队列版本:
string [ ] zfcs = [ "Enumerable" ];
try
{
string z = zfcs . Single ( );
Console . WriteLine ( z );
}
catch ( Exception yc )
{
Console.WriteLine ( $"源队列可能不是单元素队列:{yc . Message}" );
}以下示例修改自上述示例,但由于没有条件委托,且 源 为多元素队列,产生了异常:
string [ ] zfcs = [ "Enumerable" , "apple" ];
try
{
string z = zfcs . Single ( );
Console . WriteLine ( z );
}
catch ( Exception yc )
{
Console.WriteLine ( $"源队列可能不是单元素队列:{yc . Message}" );
}以下示例修改自上述示例,但添加了条件委托,使 Single 可以返回唯一的那个首字母为 a 的 apple:
string [ ] zfcs = [ "Enumerable" , "apple" ];
try
{
string z = zfcs . Single ( FF首字母a );
Console . WriteLine ( z );
}
catch ( Exception yc )
{
Console.WriteLine ( $"源队列可能不包含首字母 a 的单词:{yc . Message}" );
}
static bool FF首字母a ( string 单词 )
{
if ( 单词 . StartsWith ( 'a' ) )
return true;
return false;
}以下示例修改自上述示例,但由于首字母 a 的单词有两个,因此抛出异常:
string [ ] zfcs = [ "Enumerable" , "apple" , "all" ];
try
{
string z = zfcs . Single ( FF首字母a );
Console . WriteLine ( z );
}
catch ( Exception yc )
{
Console.WriteLine ( $"源队列可能包含多于 1 个首字母 a 的单词:{yc . Message}" );
}
static bool FF首字母a ( string 单词 )
{
if ( 单词 . StartsWith ( 'a' ) )
return true;
return false;
}以下示例使用了 SingleOrDefault 返回一个 Empty 队列的元素(使用 Single 会抛出异常):
string [ ] zfcs = [ ];
try
{
string? z = zfcs . SingleOrDefault ( ); // 这里一定返回 null
Console . WriteLine ( string . IsNullOrWhiteSpace ( z ) ? "没东西啊" : z );
}
catch ( Exception yc )
{
Console.WriteLine ( $"源队列为 null:{yc . Message}" );
}以下示例修改了上述示例,直接用默认值返回(使用 Single 会抛出异常):
string [ ] zfcs = [ ];
try
{
string z = zfcs . SingleOrDefault ( "没东西啊" ); // 这里已经不可能是 null 了
Console . WriteLine ( z );
}
catch ( Exception yc )
{
Console.WriteLine ( $"源 为 null:{yc . Message}" );
}备注
对于 Empty 队列,Single 会抛出异常。SingleOrDefault 会返回 T源 的默认值,如果要明显的返回值,应给 SingleOrDefault 的 默认值 参数指定一个特定的值,以免与队列中可能的值混淆。例如值类型的 MinValue 或者浮点数的 NaN,或者通过引用类型是否为 null 值判断输出字符串。
Skip 和 Take
修剪队列。Skip 抛除队列中起始起指定数量的元素,并返回剩余的元素。Take 返回队列中起始起指定数量的元素,并抛除剩余的元素。
public static System . Collections . Generic . IEnumerable < T源 > Skip < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , int 元素数 );
public static System . Collections . Generic . IEnumerable < T源 > Take < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , int 元素数 );
public static System . Collections . Generic . IEnumerable < T源 > Take < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Range 范围 );参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T源 | T | 源队列的元素类型 |
| 源 | IEnumerable < T源 > | 待修剪的源队列 |
| 元素数 | int | 欲自 源 中抛除或保留的元素数 |
| 范围 | Range | 欲自 源 中保留的元素的索引范围 |
返回值
| 方法 | 参数 | 类型 | 注解 |
|---|---|---|---|
| Skip | 元素数 | IEnumerable < T源 > | 一个自起始抛除 元素数 个元素后的 源 的剩余元素组成的队列 |
| Take | 元素数 | IEnumerable < T源 > | 一个自起始保留 源 的 元素数 个元素的队列 |
| Take | 范围 | IEnumerable < T源 > | 一个自起始保留 源 的 范围 内的元素的队列 |
异常
| 异常 | 注解 |
|---|---|
| ArgumentNullException | 源 为 null |
示例
以下示例分别使用 Skip 和 Take 处理一个 10 个元素的随机 int 队列:
Random SJS = new ( );
List < int > Zhss = [ ];
for ( int z = 0 ; z <=9 ; z ++ )
{
Zhss . Add ( SJS . Next ( 20 ) );
}
FF显示队列 ( "原始队列:" , Zhss );
IEnumerable < int > zhsSkip3 = Zhss . Skip ( 3 );
IEnumerable < int > zhsTake5 = Zhss . Take ( 5 );
FF显示队列 ( "Skip ( 3 ):" , zhsSkip3 );
FF显示队列 ( "Take ( 5 ):" , zhsTake5 );
Range fw = new ( 2 , 6 ); // 范围并不包括其末尾索引的元素,因此取 4 个元素
IEnumerable < int > zhsTakefw = Zhss . Take ( fw );
FF显示队列 ( "Take ( fw ):" , zhsTakefw );
static void FF显示队列<T> ( string 说明 , IEnumerable<T> 队列 )
{
Console . WriteLine ( "==================== " + 说明 + " ====================" );
Console . WriteLine ( string . Join ( ',' , 队列 ) );
}备注
此方法通过延迟执行来实现。其直接返回值是一个对象,该对象存储执行操作所需的所有信息。只有当通过直接调用对象的 GetEnumerator 方法,或在 C# 中使用 foreach、在 Visual Basic 中使用 For Each 对该对象进行枚举时,此方法所表示的查询才会执行。
Skip 和 Take 会枚举 源 并生成 元素数 个元素,或者 源 中已没有元素为止。
如果 源 . Count 少于 元素数,Skip 返回一个 Empty IEnumerable < T >(不会枚举)。如果 元素数 小于或等于零,Skip 会生成 源 中的所有元素。
如果 元素数 小于或等于零,Take 返回一个 Empty IEnumerable < T >(不会枚举)。如果 元素数 多于 源 . Count,Take 会生成 源 中的所有元素。
Take 和 Skip 方法是功能互补的。给定一个集合序列 coll 和一个整数 n,将 coll . Take ( n ) 和 coll . Skip ( n ) 的结果拼接起来,得到的序列与 coll 本身的序列相同。
即使 Take 指定的 范围 参数不在队列的有效范围内,也不会抛出异常,仅返回有效范围内的元素或 Empty。
在 Visual Basic 查询表达式语法中,Take 子句会转换为对 Take 的调用,Skip 子句会转换为对 Skip 的调用。
SkipLast 和 TakeLast
修剪队列。SkipLast 抛除队列中末尾起向前指定数量的元素,并返回剩余的元素。TakeLast 返回队列中末尾起向前指定数量的元素,并抛除剩余的元素。
public static System . Collections . Generic . IEnumerable < T源 > SkipLast < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , int 元素数 );
public static System . Collections . Generic . IEnumerable < T源 > TakeLast < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , int 元素数 );参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T源 | T | 源队列的元素类型 |
| 源 | IEnumerable < T源 > | 待修剪的源队列 |
| 元素数 | int | 欲自 源 中抛除或保留的元素数 |
返回值
| 方法 | 类型 | 注解 |
|---|---|---|
| SkipLast | IEnumerable < T源 > | 一个自末尾抛除 元素数 个元素后的 源 的剩余元素组成的队列 |
| TakeLast | IEnumerable < T源 > | 一个自末尾保留 源 的 元素数 个元素的队列 |
异常
| 异常 | 注解 |
|---|---|
| ArgumentNullException | 源 为 null |
示例
以下示例分别使用 SkipLast 和 TakeLast 处理一个 10 个元素的随机 int 队列:
Random SJS = new ( );
List < int > Zhss = [ ];
for ( int z = 0 ; z <=9 ; z ++ )
{
Zhss . Add ( SJS . Next ( 20 ) );
}
FF显示队列 ( "原始队列:" , Zhss );
IEnumerable < int > zhsSkipLast3 = Zhss . SkipLast ( 3 );
IEnumerable < int > zhsTakeLast5 = Zhss . TakeLast ( 5 );
FF显示队列 ( "SkipLast ( 3 ):" , zhsSkipLast3 );
FF显示队列 ( "TakeLast ( 5 ):" , zhsTakeLast5 );
static void FF显示队列<T> ( string 说明 , IEnumerable<T> 队列 )
{
Console . WriteLine ( "==================== " + 说明 + " ====================" );
Console . WriteLine ( string . Join ( ',' , 队列 ) );
}备注
当 元素数 参数为 0 或负值,SkipLast 的返回值是 源 的完整副本;TakeLast 将返回 Empty。
当 元素数 大于 队列 . Count,SkipLast 返回 Empty,TakeLast 返回 源 的完整副本。
SkipWhile 和 TakeWhile
SkipWhile 自队列起始,检查每个元素是否符合条件,跳过符合条件的元素,直到遇到不符合条件的元素为止,返回剩余元素;TakeWhile 自队列起始,检查每个元素是否符合条件,返回符合条件的元素,直到遇到不符合条件的元素为止。
重载
| 重载 | 注解 |
|---|---|
| SkipWhile < T源 > ( IEnumerable < T源 > , Func < T源 , Boolean > ) | 自始至终检查队列的每个元素,并在指定条件不成立时停止,并返回当前元素及其之后的全部元素 |
| SkipWhile < T源 > ( IEnumerable < T源 > , Func < T源 , Int32 , Boolean > ) | 自始至终检查队列的每个元素,并在指定条件不成立时停止,并返回当前元素及其之后的全部元素。元素的索引会在谓词函数的逻辑中使用 |
| TakeWhile < T源 > ( IEnumerable < T源 > , Func < T源 , Boolean > ) | 自始至终检查队列的每个元素,并在指定条件不成立时停止,并返回之前的符合条件的全部元素 |
| TakeWhile < T源 > ( IEnumerable < T源 > , Func < T源 , Int32 , Boolean > ) | 自始至终检查队列的每个元素,并在指定条件不成立时停止,并返回之前的符合条件的全部元素。元素的索引会在谓词函数的逻辑中使用 |
public static System . Collections . Generic . IEnumerable < T源 > SkipWhile < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , bool > 条件委托 );
public static System . Collections . Generic . IEnumerable < T源 > SkipWhile < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , int 索引 , bool > 条件委托 );
public static System . Collections . Generic . IEnumerable < T源 > TakeWhile < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , bool > 条件委托 );
public static System . Collections . Generic . IEnumerable < T源 > TakeWhile < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , int 索引 , bool > 条件委托 );参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T源 | T | 源队列的元素类型 |
| 源 | IEnumerable < T源 > | 欲修剪的源队列 |
| 条件索引 | Func < T源 , bool > Func < T源 , int 索引 , bool > | 测试每个源队列的元素是否满足条件的函数;可以附带第二个参数表示其索引 |
返回值
| 方法 | 类型 | 注解 |
|---|---|---|
| SkipWhile | IEnumerable < T源 > | 一个自起始抛除不符合 条件索引 指定的条件后的 源 的剩余元素组成的队列 |
| TakeWhile | IEnumerable < T源 > | 一个自起始保留 源 的符合 条件索引 的元素的队列 |
异常
| 异常 | 注解 |
|---|---|
| ArgumentNullException | 源 和/或 条件委托 为 null |
示例
以下示例产生了一个 10 个数值的,范围为 0 ~ 19 的随机数队列。并对其默认顺序排序(自小到大)。
随后使用了 TakeWhile 并用 FF小于10 委托选取了队列中自起始小于 10 的数值形成队列(ZhsTakeWhile小于10),TakeWhile 将在遇到大于等于 10 的元素时结束。
随后使用了 SkipWhile 同样用 FF小于10 委托自队列起始跳过所有的小于 10 的数值,并在遇到第一个大于等于 10 的数值时,将该元素及队列剩余元素形成队列(ZhsSkipWhile小于10)。
这样形成了两个以 10 为分界线的整数队列。然后对它们使用 Where 方法并使用 FF整除2 委托,从而分别挑出小于 10 和大于等于 10 的随机数中的所有偶数。
Random SJS = new ( );
List < int > Zhss = [ ];
for ( int z = 0 ; z <=9 ; z ++ )
{
Zhss . Add ( SJS . Next ( 20 ) );
}
FF显示队列 ( "原始队列:" , Zhss );
Zhss . Sort ( ); // 这一步是必须的
IEnumerable < int > zhsTakeWhile小于10 = Zhss . TakeWhile ( FF小于10 );
IEnumerable < int > zhsSkipWhile小于10 = Zhss . SkipWhile ( FF小于10 );
FF显示队列 ( "小于 10 的偶数:" , zhsTakeWhile小于10 . Where ( FF整除2 ) );
FF显示队列 ( "大于等于 10 的偶数:" , zhsSkipWhile小于10 . Where ( FF整除2 ) );
static bool FF小于10 ( int 整数 )
{
if ( 整数 >= 10 ) return false;
return true;
}
static bool FF整除2 ( int 整数 )
{
if ( 整数 % 2 == 0 ) return true;
return false;
}
static void FF显示队列<T> ( string 说明 , IEnumerable<T> 队列 )
{
Console . WriteLine ( "==================== " + 说明 + " ====================" );
Console . WriteLine ( string . Join ( ',' , 队列 ) );
}以下示例使用随机数产生了本学期 10 次考试的分数(int 队列),由于没有排序,只能按照索引进行分组,即分为上半学期和下半学期,并输出每个半学期的及格分数:
Random SJS = new ( );
List < int > Zhss分数 = [ ];
for ( int z = 0 ; z <=9 ; z ++ )
{
Zhss分数 . Add ( SJS . Next ( 40 , 101 ) );
}
FF显示队列 ( "原始队列:" , Zhss分数 );
IEnumerable < int > zhss前5 = Zhss分数 . TakeWhile ( ( f , suoyin ) => suoyin < 5 );
IEnumerable < int > zhss后5 = Zhss分数 . SkipWhile ( ( f , suoyin ) => suoyin < 5 );
IEnumerable < int > zhss前5几次及格 = Zhss分数 . TakeWhile ( ( f , suoyin ) => suoyin < 5 ) . Where ( FF及格 );
IEnumerable < int > zhss后5几次及格 = Zhss分数 . SkipWhile ( ( f , suoyin ) => suoyin < 5 ) . Where ( FF及格 );
FF显示队列 ( "前五次考试:" , zhss前5 );
FF显示队列 ( "前五次考试几次及格:" , zhss前5几次及格 );
FF显示队列 ( "后五次考试:" , zhss后5 );
FF显示队列 ( "后五次考试几次及格:" , zhss后5几次及格 );
static bool FF及格 ( int 整数 )
{
if ( 整数 >= 60 ) return true;
return false;
}
static void FF显示队列<T> ( string 说明 , IEnumerable<T> 队列 )
{
Console . WriteLine ( "==================== " + 说明 + " ====================" );
Console . WriteLine ( string . Join ( ',' , 队列 ) );
}备注
此方法通过延迟执行来实现。其直接返回值是一个对象,该对象存储执行操作所需的所有信息。只有当通过直接调用对象的 GetEnumerator 方法,或在 C# 中使用 foreach、在 Visual Basic 中使用 For Each 对该对象进行枚举时,此方法所表示的查询才会执行。
SkipWhile 方法会使用 条件委托 测试 源 中的每个元素,若结果为 true 则跳过该元素。当谓词函数对某个元素返回 false 后(或没有元素可枚举),会生成该元素以及 源 中的剩余元素,且不再调用 条件委托。
TakeWhile 方法会使用 条件委托 测试 源 中的每个元素,若结果为 true 则选取该元素。当谓词函数对某个元素返回 false 后,会停止选取并返回以前生成的所有元素组成的队列,且不再调用 条件委托。
如果 条件委托 对 源 中的所有元素都返回 true,SkipWhile 返回一个空的 IEnumerable < T源 >;TakeWhile 返回一个 源 的完整副本。
条件委托 的第一个参数表示要测试的元素。第二个参数(可选的)表示该元素在 源 中的从零开始的索引。
无论使用哪个条件委托,若是使用 SkipWhile 和/或 TakeWhile 对队列进行分区,必须知道分区的分界线,即对于排序的(示例 1)的元素按某个值分区;或对未排序的(示例 2)的元素按索引(未排序的队列唯一的有序的)分区。否则,其结果是很奇怪的。
少见的示例是对某个文本(已形成每段一个元素的队列)的筛选。例如仅选取前三段,Take ( 3 ) 将选取前三段,但可能是空行,TakeWhile ( ( duanluo , suoyin ) => suoyin < 3 && !string . IsNullOrWhiteSpace ( duanluo ) ) 将选取前三段里仅仅不是空行的(空行将被忽略,若三段皆为空行则是空集);仅跳过前三段,Skip ( 3 ) 将跳过前三段,虽然可能是空行,SkipWhile ( ( duanluo , suoyin ) => suoyin < 3 || !string . IsNullOrWhiteSpace ( duanluo ) ) 也是跳过前三段(空行也被跳过,实际就是 Skip ( 3 ))。
TakeWhile 和 SkipWhile 方法是函数式互补的。给定一个集合序列 coll 和一个纯函数 p,将 coll . TakeWhile ( p ) 和 coll . SkipWhile ( p ) 的结果拼接起来,得到的序列与 coll 相同。
在 Visual Basic 查询表达式语法中,Skip While 子句会转换为对 SkipWhile 的调用,Take While 子句会转换为对 TakeWhile 的调用。
Sum
求一个值类型(或者至少要实现 IAdditionOperators 接口的对象)的队列的和值。
重载
| 重载 | 注解 |
|---|---|
| Sum ( IEnumerable < T源 > ) | 计算 T源 类型序列的和(T源 必须是内置值类型或实现 IAdditionOperators 接口的类型) |
| Sum ( IEnumerable < Nullable < T源 > > ) | 计算可 null T源 类型序列的和(T源 必须是内置值类型或实现 IAdditionOperators 接口的类型) |
| Sum < T源 > ( IEnumerable < T源 > , Func < T源 , T结果 > ) | 计算 T源 类型序列的和(T源 必须是内置值类型或实现 IAdditionOperators 接口的类型),返回值为 T结果 类型 |
public static T源 Sum ( this System . Collections . Generic . IEnumerable < T源 > 源 );
public static T源? Sum ( this System . Collections . Generic . IEnumerable < T源? > 源 );
public static T结果 Sum < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , T结果 > 结果选择器 );参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T源 | T | 源队列的元素类型 |
| 源 | IEnumerable < T源 > IEnumerable < T源? > | 欲求和的队列 |
| T结果 | T | 通过结果选择器返回的“总和”的类型 |
| 结果选择器 | Func < T源 , T结果 > | 以 源 的元素生成的和的表现形式 |
返回值
| 类型 | 注解 |
|---|---|
| T源 T结果 | 队列的总和。对于可空类型,null 均被作为 0 处理 |
异常
| 异常 | 注解 |
|---|---|
| ArgumentNullException | 源 和/或 结果选择器 为 null |
| OverflowException | 总和超出 T源 或 T结果 的描述范围 |
示例
以下示例分别演示了求一个 int 队列的总和、平均数和偶数和:
int [ ] Zhss = [ 2 , 3 , 6 , 7 , 11 ];
int zhs总和 = Zhss . Sum ( );
double sjd平均值 = Zhss . Average ( );
FF显示队列 ( "原始队列:" , Zhss );
Console . WriteLine ( $"总和:{zhs总和},平均值:{sjd平均值}" );
int zhs偶数和 = Zhss . Where ( FF偶数 ) . Sum ( );
Console . WriteLine ( $"偶数和:{zhs偶数和} " );
static bool FF偶数 ( int 整数 )
{
if ( 整数 % 2 == 0 ) return true;
return false;
}以下示例展示了使用结果选择器计算一组小妹妹的体重:
LEI小妹妹 [ ] MMs =
[
new LEI小妹妹 ( "肖晓笑" , 53.5 ),
new LEI小妹妹 ( "周洲舟" , 48.5 ),
new LEI小妹妹 ( "彭芃芃" , 52 ),
];
double sjd总体重 = MMs . Sum ( m => m . 体重 );
double sjd平均体重 = MMs . Average ( m => m . 体重 );
Console . WriteLine ( $"小妹妹们总共重:{sjd总体重}kg,平均 {sjd平均体重:N2}kg" );
public class LEI小妹妹 ( string 姓名 , double 体重 )
{
public string 姓名 { get; set; } = 姓名;
public double 体重 { get; set; } = 体重;
}备注
如果 源 中不包含任何元素(Count 为零),Sum 返回 0。元素若为 null,将不参与计算,若所有元素(结果选择器选择的)均为 null,也返回 0。
结果选择器 会将 源 中的非值类型转换为值类型(可空),此时可以使用 Sum 计算任意非值类型队列的总和,例如示例 2 计算小妹妹们的体重。
在 Visual Basic 查询表达式语法中,Aggregate Into Sum ( ) 子句会转换为对 Sum 的调用。
ThenBy 和 ThenByDescending
ThenBy 和 ThenByDescending 对已组排序的队列(由 Order、OrderDescending、OrderBy 或 OrderByDescending 方法返回)进行后续的排序(升序或降序)。它是一个子句,需在某组排序语句之后使用。按照组内的对象,可以添加无限的 ThenBy 或 ThenByDescending,以继续按照其某字段排序。
重载
| 重载 | 注解 |
|---|---|
| ThenBy < T源 , T键 > ( IOrderedEnumerable < T源 > , Func < T源 , T键 > ) | 使用默认键比较器,继续排序队列(升序) |
| ThenBy < T源 , T键 > ( IOrderedEnumerable < T源 > , Func < T源 , T键 > , IComparer < T键 > ) | 使用指定键比较器,继续排序队列(升序) |
| ThenByDescending < T源 , T键 > ( IOrderedEnumerable < T源 > , Func < T源 , T键 > ) | 使用默认键比较器,继续排序队列(降序) |
| ThenByDescending < T源 , T键 > ( IOrderedEnumerable < T源 > , Func < T源 , T键 > , IComparer < T键 > ) | 使用指定键比较器,继续排序队列(降序) |
public static System . Linq . IOrderedEnumerable < T源 > ThenBy < T源 , T键 > ( this System . Linq . IOrderedEnumerable < T源 > 源 , Func < T源 , T键 > 键选择器 );
public static System . Linq . IOrderedEnumerable < T源 > ThenBy < T源 , T键 > ( this System . Linq . IOrderedEnumerable < T源 > 源 , Func < T源 , T键 > 键选择器 , System . Collections . Generic . IComparer < T键 >? 键比较器 );
public static System . Linq . IOrderedEnumerable < T源 > ThenByDescending < T源 , T键 > ( this System . Linq . IOrderedEnumerable < T源 > 源 , Func < T源 , T键 > 键选择器 );
public static System . Linq . IOrderedEnumerable < T源 > ThenByDescending < T源 , T键 > ( this System . Linq . IOrderedEnumerable < T源 > 源 , Func < T源 , T键 > 键选择器 , System . Collections . Generic . IComparer < T键 >? 键比较器 );参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T源 T键 | T | 源队列的元素类型和生成键的元素类型 |
| 源 | IOrderedEnumerable < T源 > | 欲继续排序的队列 |
| 键选择器 | Func < T源 , T键 > | 继续排序的键生成器 |
| 键比较器 | IComparer < T键 >? | 对键选择器生成的键比较的比较器,未指定或为 null 则为 默认比较器 |
返回值
| 类型 | 注解 |
|---|---|
| IOrderedEnumerable < T源 > | 对元素(已分组)进行组内排序的结果队列 |
异常
| 异常 | 注解 |
|---|---|
| ArgumentNullException | 源 和/或 键选择器 为 null |
示例
以下示例展示了对一个 int 队列的排序,Order 作为主排序只关心它是不是偶数,ThenBy 则关心它们之间的大小关系:
int [ ] Zhss =
[
3 , 7 , 5 , 6 , 4 , 9 ,
];
FF显示队列 ( "原始队列:" , Zhss );
IEnumerable < int > chx未排序的偶数 = Zhss . OrderBy ( FF偶数 );
IEnumerable < int > chx排序的偶数 = Zhss . OrderBy ( FF偶数 ) . ThenByDescending ( x => x );
FF显示队列 ( "未排序的偶数队列:" , chx未排序的偶数 );
FF显示队列 ( "排序后的偶数队列:" , chx排序的偶数 );
static bool FF偶数 ( int 整数 )
{
if ( 整数 % 2 == 0 ) return true;
return false;
}
static void FF显示队列<T> ( string 说明 , IEnumerable<T> 队列 )
{
Console . WriteLine ( "==================== " + 说明 + " ====================" );
Console . WriteLine ( string . Join ( ',' , 队列 ) );
}以下示例展示了多重 ThenBy 和 ThenByDescending,使用了小妹妹的身高、体重和姓名来排序:
LEI小妹妹 [ ] MMs =
[
new LEI小妹妹 ( "肖晓笑" , 156 , 53.5 ),
new LEI小妹妹 ( "肖笑笑" , 166 , 55.5 ),
new LEI小妹妹 ( "肖笑晓" , 166 , 55.5 ),
new LEI小妹妹 ( "周洲舟" , 177 , 48.5 ),
new LEI小妹妹 ( "周一舟" , 164 , 48.5 ),
new LEI小妹妹 ( "彭芃芃" , 166 , 52 ),
new LEI小妹妹 ( "彭啥啥" , 172 , 52.5 ),
];
IEnumerable < LEI小妹妹 > MMs高重姓名 = MMs . OrderBy ( m => m . 身高 ) . ThenBy ( m => m . 体重 ) . ThenByDescending ( m => m . 姓名 );
FF显示队列 ( "身高、体重再姓名排序的小妹妹们:" , MMs高重姓名 );
static void FF显示队列<T> ( string 说明 , IEnumerable<T> 队列 )
{
Console . WriteLine ( "==================== " + 说明 + " ====================" );
Console . WriteLine ( string . Join ( ',' , 队列 ) );
}
public class LEI小妹妹 ( string 姓名 , double 身高 , double 体重 )
{
public string 姓名 { get; set; } = 姓名;
public double 体重 { get; set; } = 体重;
public double 身高 { get; set; } = 身高;
public override string ToString ( )
{
return $"{姓名}\t{身高}cm\t{体重}kg";
}
}备注
此方法通过延迟执行来实现。其直接返回值是一个对象,该对象包含执行该操作所需的所有信息。只有当通过直接调用对象的 GetEnumerator 方法,或在 C# 中使用 foreach、在 Visual Basic 中使用 For Each 对该对象进行枚举时,此方法所表示的查询才会执行。
要按元素本身的值对序列进行排序,请为 键选择器 指定标识函数(C# 中为 x => x,Visual Basic 中为Function ( x ) x)。
ThenBy 和 ThenByDescending 被定义为扩展 IOrderedEnumerable < T元素 > 类型,而这也是这些方法的返回类型。该设计允许你通过应用任意数量的 ThenBy 或 ThenByDescending 方法来指定多个排序条件。
注意:由于 IOrderedEnumerable < T元素 > 继承自 IEnumerable < T >,你可以在调用 OrderBy、OrderByDescending、ThenBy 或 ThenByDescending 的结果上调用 OrderBy 或 OrderByDescending。这样做会引入一种新的主排序方式,该方式会忽略之前已建立的排序规则。
如果 键比较器 为 null 或未指定,则使用默认比较器 Default 来比较键。
此方法执行稳定排序;也就是说,如果两个元素的键相等,则元素的顺序会保持不变。相比之下,不稳定排序不会保留具有相同键的元素的顺序。
ToArray
返回一个数组,该数组的元素由队列的元素组成。 public static T源 [ ] ToArray < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 );
参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T源 | T | 源队列的元素类型 |
| 源 | IEnumerable < T源 > | 欲转换的源队列 |
返回值
| 类型 | 注解 |
|---|---|
| T源 [ ] | 将 源 队列转换为数组 |
异常
| 异常 | 注解 |
|---|---|
| ArgumentNullException | 源 为 null |
示例
以下示例是最简单的,将一个 int 队列转换为 int 数组,结果将局限于仅使用数组的方法:
List < int > Zhss = [ 7 , 5 , 4 , 6 , 2 , 6 ];
int [ ] zhs转换 = [ .. Zhss ];
FF显示队列 ( "转换后的数组:" , zhs转换 );以下示例是稍微复杂点的,将小妹妹的队列转换为 string 队列,只是其姓名而已:
LEI小妹妹 [ ] MMs =
[
new LEI小妹妹 ( "肖晓笑" , 156 , 53.5 ),
new LEI小妹妹 ( "肖笑笑" , 166 , 55.5 ),
new LEI小妹妹 ( "肖笑晓" , 166 , 55.5 ),
new LEI小妹妹 ( "周洲舟" , 177 , 48.5 ),
new LEI小妹妹 ( "周一舟" , 164 , 48.5 ),
new LEI小妹妹 ( "彭芃芃" , 166 , 52 ),
new LEI小妹妹 ( "彭啥啥" , 172 , 52.5 ),
];
string [ ] zfc姓名s = [ .. MMs . Select ( m => m . 姓名 ) ]; // 等同于 MMs . Select ( m => m . 姓名 ) . ToArray ( )
FF显示队列 ( "小妹妹的名字:" , zfc姓名s );
static void FF显示队列<T> ( string 说明 , IEnumerable<T> 队列 )
{
Console . WriteLine ( "==================== " + 说明 + " ====================" );
Console . WriteLine ( string . Join ( ',' , 队列 ) );
}
public class LEI小妹妹 ( string 姓名 , double 身高 , double 体重 )
{
public string 姓名 { get; set; } = 姓名;
public double 体重 { get; set; } = 体重;
public double 身高 { get; set; } = 身高;
public override string ToString ( )
{
return $"{姓名}\t{身高}cm\t{体重}kg";
}
}备注
ToArray < T源 > ( IEnumerable < T源 > ) 方法会立即执行查询并返回一个包含查询结果的数组。你可以将此方法追加到查询中,以获取查询结果的缓存副本。
ToList 具有类似的行为,但返回的是 List < T > 而非 Array。
ToDictionary
自队列创建一个词典。
重载
| 重载 | 注解 |
|---|---|
| ToDictionary < T键 , T值 > ( IEnumerable < KeyValuePair < T键 , T值 > > ) | 根据键类型的默认比较器,自 源队列 创建词典 |
| ToDictionary < T键 , T值 > ( IEnumerable < ValueTuple < T键 , T值 > > ) | 根据键类型的默认比较器,自 源队列 创建词典 |
| ToDictionary < T键 , T值 > ( IEnumerable < KeyValuePair < T键 , T值 > > , IEqualityComparer < T键 > ) | 根据指定的键比较器自 源队列 创建词典 |
| ToDictionary < T键 , T值 > ( IEnumerable < ValueTuple < T键 , T值 > > , IEqualityComparer < T键 > ) | 根据指定的键相等比较器,自 源队列 创建词典 |
| ToDictionary < T源 , T键 , T元素 > ( IEnumerable < T源 > , Func < T源 , T键 > , Func < T源 , T元素 > ) | 根据指定的键选择器函数和元素表达器函数,自 源队列 创建词典 |
| ToDictionary < T源 , T键 , T元素 > ( IEnumerable < T源 > , Func < T源 , T键 > , Func < T源 , T元素 > , IEqualityComparer < T键 > ) | 根据指定的键选择器函数、比较器和元素表达器函数,自 源队列 创建词典 |
| ToDictionary < T源 , T键 > ( IEnumerable < T源 > , Func < T源 , T键 > ) | 根据指定的键选择器函数,自 源队列 创建词典 |
| ToDictionary < T源 , T键 > ( IEnumerable < T源 > , Func < T源 , T键 > , IEqualityComparer < T键 > ) | 根据指定的键选择器函数和键比较器,自 源队列 创建词典 |
public static System . Collections . Generic . Dictionary < T键 , T值 > ToDictionary < T键 , T值 > ( this System . Collections . Generic . IEnumerable < System . Collections . Generic . KeyValuePair < T键 , T值 > > 键值对 );
public static System . Collections . Generic . Dictionary < T键 , T值 > ToDictionary < T键 , T值 > ( this System . Collections . Generic . IEnumerable < ( T键 键 , T值 值 ) > 可枚举对象 );
public static System . Collections . Generic . Dictionary < T键 , T值 > ToDictionary < T键 , T值 > ( this System . Collections . Generic . IEnumerable < System . Collections . Generic . KeyValuePair < T键 , T值 > > 键值对 , System . Collections . Generic . IEqualityComparer < T键 >? 键比较器 );
public static System . Collections . Generic . Dictionary < T键 , T值 > ToDictionary < T键 , T值 > ( this System . Collections . Generic . IEnumerable < ( T键 键 , T值 值 ) > 可枚举对象 , System . Collections . Generic . IEqualityComparer < T键 >? 键比较器 );
public static System . Collections . Generic . Dictionary < T键 , T元素 > ToDictionary < T源 , T键 , T元素 > ( this System . Collections . Generic . IEnumerable < T源 > 可枚举对象 , Func < T源 , T键 > 键选择器 , Func < T源 , T元素 > 元素表达器 );
public static System . Collections . Generic . Dictionary < T键 , T元素 > ToDictionary < T源 , T键 , T元素 > ( this System . Collections . Generic . IEnumerable < T源 > 可枚举对象 , Func < T源 , T键 > 键选择器 , Func < T源 , T元素 > 元素表达器 , System . Collections . Generic . IEqualityComparer < T键 >? 键比较器 );
public static System . Collections . Generic . Dictionary < T键 , T源 > ToDictionary < T源 , T键 > ( this System . Collections . Generic . IEnumerable < T源 > 可枚举对象 , Func < T源 , T键 > 键选择器 );
public static System . Collections . Generic . Dictionary < T键 , T源 > ToDictionary < T源 , T键 > ( this System . Collections . Generic . IEnumerable < T源 > 可枚举对象 , Func < T源 , T键 > 键选择器 , System . Collections . Generic . IEqualityComparer < T键 >? 键比较器 );参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T键 | T | 键选择器生成的元素类型 |
| T值 | T | 返回词典的值的元素类型 |
| 键值对 可枚举对象 | KeyValuePair < T键 , T值 > > IEnumerable < ( T键 键 , T值 值 ) > | 创建的词典的键和值 |
| 键比较器 | IEqualityComparer < T键 >? | 对于键的排序或是否相等的比较器,null 或未指定使用默认比较器 |
| 键选择器 | Func < T源 , T键 > | 选择对于元素比较的键 |
| 元素表达器 | Func < T源 , T元素 > | 对键值对或可枚举对象的表达方式 |
返回值
| 类型 | 注解 |
|---|---|
| Dictionary < T键 , T元素 > | 一个可能包含 键选择器 选择的 键 的词典(键与值的内容) |
异常
| 异常 | 注解 |
|---|---|
| ArgumentException | 键选择器 生成两个元素的键同值 |
| ArgumentNullException | 源 或 键选择器(包括其返回值为 null)或 元素表达器 为 null |
示例
以下示例展示了如何判断一个 int 队列的奇偶性,由于 Dictionary 的特性,其元素不能是重复的:
List<int> Zhss = [ 7, 5, 4, 6, 2 ];
// 键即数值本身,由于 Dictionary 的限制,不能是重复值
Dictionary < int , string > zhs转换 = Zhss . ToDictionary
(
x => x, // 键:用数字自己(唯一不重复)
x => x % 2 == 0 ? "偶数" : "奇数" // 元素表达器:string,匹配类型
);
FF显示队列 ( "转换后的词典:" , zhs转换 );
static void FF显示队列 < T > ( string 说明 , IEnumerable < T > 队列 )
{
Console . WriteLine ( "==================== " + 说明 + " ====================" );
Console . WriteLine ( string . Join ( ',' , 队列 ) );
}以下示例使用了小妹妹的 BMI 作为键来创建一个以小妹妹队列为基础的词典:
LEI小妹妹 [ ] MMs =
[
new LEI小妹妹 ( "肖晓笑" , 156 , 53.5 ),
new LEI小妹妹 ( "肖笑笑" , 167 , 55.5 ),
new LEI小妹妹 ( "肖笑晓" , 168 , 55.5 ),
new LEI小妹妹 ( "周洲舟" , 177 , 48.5 ),
new LEI小妹妹 ( "周一舟" , 164 , 48.5 ),
new LEI小妹妹 ( "彭芃芃" , 166 , 52 ),
new LEI小妹妹 ( "彭啥啥" , 172 , 52.5 ),
];
Dictionary < double , LEI小妹妹 > CD小妹妹 = MMs . ToDictionary ( m => ( m . 体重 / Math . Pow ( ( double ) m . 身高 / 100 , 2 ) ) );
FF显示队列 ( "以 BMI 为键值的小妹妹们:" , CD小妹妹 );备注
未指定或指定比较器但为 null,则使用键值类型的默认比较器比较元素生成的键值。
ToHashSet
自队列创建一个 HashSet。
重载
| 重载 | 注解 |
|---|---|
| ToHashSet < T源 > ( IEnumerable < T源 > ) | 自队列创建一个 HashSet,使用默认比较器比较键值 |
| ToHashSet < T源 > ( IEnumerable < T源 > , IEqualityComparer < T源 > ) | 自队列创建一个 HashSet,使用指定比较器比较键值 |
public static System . Collections . Generic . HashSet < T源 > ToHashSet < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 );
public static System . Collections . Generic . HashSet < T源 > ToHashSet < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , System . Collections . Generic . IEqualityComparer < T源 >? 比较器 );参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T源 | T | 源队列的元素类型 |
| 源 | IEnumerable < T源 > | 欲创建 HashSet 的源队列 |
| 比较器 | IEqualityComparer < T源 >? | 用于比较键值的比较器 |
返回值
| 类型 | 注解 |
| HashSet < T源 > | 经过去重的顺序不变的源队列元素组成的 HashSet |
异常
| 异常 | 注解 |
|---|---|
| ArgumentNullException | 源 为 null |
示例
以下示例展示了 ToHashSet 的用法(返回值去重,但并不改变源队列的元素顺序):
List<int> Zhss = [ 7, 5, 4, 6, 2 , 2 ];
HashSet < int > ZhssHash = [ .. Zhss ]; // 即 Zhss . ToHashSetToList
自队列创建一个 List。 public static System . Collections . Generic . List < T源 > ToList < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 );
参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T源 | T | 源队列的元素类型 |
| 源 | IEnumerable < T源 > | 欲创建 List 的源队列 |
返回值
| 类型 | 注解 |
|---|---|
| List < T源 > | 一个由源队列的所有元素组成的 List |
异常
| 异常 | 注解 |
|---|---|
| ArgumentNullException | 源 为 null |
示例
以下示例创建了一个 List,其元素来自于小妹妹队列的元素的身高字段:
LEI小妹妹 [ ] MMs =
[
new LEI小妹妹 ( "肖晓笑" , 156 , 53.5 ),
new LEI小妹妹 ( "肖笑笑" , 167 , 55.5 ),
new LEI小妹妹 ( "肖笑晓" , 168 , 55.5 ),
new LEI小妹妹 ( "周洲舟" , 177 , 48.5 ),
new LEI小妹妹 ( "周一舟" , 164 , 48.5 ),
new LEI小妹妹 ( "彭芃芃" , 166 , 52 ),
new LEI小妹妹 ( "彭啥啥" , 172 , 52.5 ),
];
List < int > Zhss身高 = [ .. MMs . Select ( m => m . 身高 ) ]; // 即 . ToList ( )
FF显示队列 ( "小妹妹们的身高:" , Zhss身高 );
static void FF显示队列<T> ( string 说明 , IEnumerable<T> 队列 )
{
Console . WriteLine ( "==================== " + 说明 + " ====================" );
Console . WriteLine ( string . Join ( ',' , 队列 ) );
}
public class LEI小妹妹 ( string 姓名 , int 身高 , double 体重 )
{
public string 姓名 { get; set; } = 姓名;
public double 体重 { get; set; } = 体重;
public int 身高 { get; set; } = 身高;
public override string ToString ( )
{
return $"{姓名}\t{身高}cm\t{体重}kg";
}
}ToLookup
从 IEnumerable < T > 创建一个泛型 Lookup < T键 , T元素 >,按照形成的键值分组队列中的元素。
重载
| 重载 | 注解 |
|---|---|
| ToLookup < T源 , T键 > ( IEnumerable < T源 > , Func < T源 , T键 > ) | 通过指定键选择器并使用默认键值比较器,自队列创建一个 Lookup < T键 , T源 > |
| ToLookup < T源 , T键 > ( IEnumerable < T源 > , Func < T源 , T键 > , IEqualityComparer < T键 > ) | 通过指定键选择器并使用指定键值比较器,自队列创建一个 Lookup < T键 , T源 > |
| ToLookup < T源 , T键 , T元素 > ( IEnumerable < T源 > , Func < T源 , T键 > , Func < T源 , T元素 > ) | 通过指定键选择器并使用默认键值比较器,自队列创建一个 Lookup < T键 , T元素 >,每个元素使用元素表达器表达 |
| ToLookup < T源 , T键 , T元素 > ( IEnumerable < T源 > , Func < T源 , T键 > , Func < T源 , T元素 > , IEqualityComparer < T键 > ) | 通过指定键选择器并使用指定键值比较器,自队列创建一个 Lookup < T键 , T元素 >,每个元素使用元素表达器表达 |
public static System . Linq . ILookup < T键 , T源 > ToLookup < T源 , T键 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , T键 > 键选择器 );
public static System . Linq . ILookup < T键 , T源 > ToLookup < T源 , T键 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , T键 > 键选择器 , System . Collections . Generic . IEqualityComparer < T键 >? 键比较器 );
public static System . Linq . ILookup < T键 , T源 > ToLookup < T源 , T键 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , T键 > 键选择器 , Func < T源 , T元素 > 元素表达器 );
public static System . Linq . ILookup < T键 , T源 > ToLookup < T源 , T键 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , T键 > 键选择器 , Func < T源 , T元素 > 元素表达器 , System . Collections . Generic . IEqualityComparer < T键 >? 键比较器 );参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T键 | T | 按源队列的每个元素生成的键值的类型 |
| T源 | T | 源队列的元素类型 |
| 源 | IEnumerable < T源 > | 欲生成 Lookup 队列的源队列 |
| 键选择器 | Func < T源 , T键 > | 对源队列的每个元素生成键值的函数 |
| 键比较器 | IEqualityComparer < T键 >? | 对每个键值进行比较的比较器 |
| T元素 | T | 对于每个元素的表达方式的类型(元素表达器的返回值类型) |
| 元素表达器 | Func < T源 , T元素 > | 对于每个元素的表达方式的函数 |
返回值
| 类型 | 注解 |
|---|---|
| ILookup < T键 , T源 > ILookup < T键 , T元素 > | 一个按键分组的元素列表,包含键值和值,分组中的值的顺序与 源 相同 |
异常
| 异常 | 注解 |
|---|---|
| ArgumentNullException | 源 或 键选择器 或 元素表达器 为 null |
示例
以下示例展示了 ToLookup 将小妹妹按身高分成三组:
LEI小妹妹 [ ] MMs =
[
new LEI小妹妹 ( "肖晓笑" , 156 , 53.5 ),
new LEI小妹妹 ( "肖笑笑" , 167 , 55.5 ),
new LEI小妹妹 ( "肖笑晓" , 168 , 55.5 ),
new LEI小妹妹 ( "周洲舟" , 177 , 48.5 ),
new LEI小妹妹 ( "周一舟" , 164 , 48.5 ),
new LEI小妹妹 ( "彭芃芃" , 166 , 52 ),
new LEI小妹妹 ( "彭啥啥" , 172 , 52.5 ),
];
ILookup < string , string > LU高矮 =
MMs . ToLookup (
m =>
{
if ( m . 身高 < 160 ) return "太矮了:";
if ( m . 身高 > 170 ) return "太高了:";
return "身材合适:";
},
m => m . 姓名 );
foreach ( var zu in LU高矮 )
{
Console . WriteLine ( zu . Key );
foreach ( var m in zu )
{
Console . WriteLine ( $" {m}" );
}
}
public class LEI小妹妹 ( string 姓名 , int 身高 , double 体重 )
{
public string 姓名 { get; set; } = 姓名;
public double 体重 { get; set; } = 体重;
public int 身高 { get; set; } = 身高;
public override string ToString ( )
{
return $"{姓名}\t{身高}cm\t{体重}kg";
}
}备注
ToLookup 方法返回一个 Lookup < T键 , T元素 >,这是一种将键映射到值集合的一对多字典。Lookup < T键 , T元素 > 与 Dictionary < T键 , T元素 > 不同,后者是将键一对一映射到单个值。
当未指定 键比较器 或 键比较器 为 null,使用默认的相等比较器 Default 来比较键。
TryGetNonEnumeratedCount
尝试在不强制枚举的情况下确定序列中的元素数量。 public static bool TryGetNonEnumeratedCount < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , out int 元素数 );
参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T源 | T | 源队列的元素类型 |
| 源 | IEnumerable < T源 > | 欲统计元素个数的队列 |
| 元素数 | int | 其数值与方法的返回值有关 |
返回值
| 类型 | 注解 |
|---|---|
| bool | 若队列无需枚举即可获知元素数量,则为 true,此时 元素数 即为 源 . Count;否则为 false,此时 元素数 为 0 |
示例
以下示例省略了对象的类的描述,参见以前的示例。
bool T结果 = LU高矮 . TryGetNonEnumeratedCount ( out int 元素数 );
Console . WriteLine ( $"LU高矮 的元素数 {元素数},因为 TryGetNonEnumeratedCount 结果是 {T结果}" );
var 姓名筛选 = MMs . Where ( m => m . 姓名 . StartsWith ( '周' ) );
T结果 = 姓名筛选 . TryGetNonEnumeratedCount ( out 元素数 );
Console . WriteLine ( $"姓名筛选 的元素数 {元素数},因为 TryGetNonEnumeratedCount 结果是 {T结果}" );备注
该方法执行一系列类型测试,识别出无需枚举即可确定其计数的常见子类型。这包括 ICollection < T >、ICollection 以及 LINQ 实现中使用的内部类型。
该方法通常是常数时间操作,但最终这取决于底层集合实现的复杂度特性。
Union
生成两个队列的并集。
重载
| 重载 | 注解 |
|---|---|
| Union < T源 > ( IEnumerable < T源 > , IEnumerable < T源 > ) | 使用默认比较器生成两个队列的并集 |
| Union < T源 > ( IEnumerable < T源 > , IEnumerable < T源 > , IEqualityComparer < T源 > ) | 使用指定比较器生成两个队列的并集 |
public static System . Collections . Generic . IEnumerable < T源 > Union < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 队列1 , System . Collections . Generic . IEnumerable < T源 > 队列2 );
public static System . Collections . Generic . IEnumerable < T源 > Union < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 队列1 , System . Collections . Generic . IEnumerable < T源 > 队列2 , System . Collections . Generic . IEqualityComparer < T源 >? 比较器 );参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T源 | T | 欲求合集的两个队列的元素类型,即结果的元素类型 |
| 队列1 队列2 | IEnumerable < T源 > | 欲求合集的两个队列 |
| 比较器 | IEqualityComparer < T源 >? | 对于 队列1 和 队列2 中的元素是否相等的比较器。null 或未指定则为默认比较器 |
返回值
| 类型 | 注解 |
|---|---|
| IEnumerable < T源 > | 一个包含 队列1 和 队列2 中的所有元素且按照 比较器 去重的队列 |
异常
| 异常 | 注解 |
|---|---|
| ArgumentNullException | 队列1 或 队列2 为 null |
示例
第一个示例展示了两个 int 队列的合集(使用默认比较器):
List < int > Zhss1 = [ 3 , 5 , 6 , 4 , 3 ];
List < int > Zhss2 = [ 9 , 5 , 1 , 1 ];
IEnumerable<int> Zhss合集 = Zhss1 . Union ( Zhss2 );
FF显示队列 ( $"{string . Join ( ',' , Zhss1 )} 和 {string . Join ( ',' , Zhss2 )} 的合集:" , Zhss合集 );
static void FF显示队列<T> ( string 说明 , IEnumerable<T> 队列 )
{
Console . WriteLine ( "==================== " + 说明 + " ====================" );
Console . WriteLine ( string . Join ( ',' , 队列 ) );
}以下示例分别展示了使用默认比较器和使用指定比较器的对图形队列的合集,默认比较器时,由于 图形 对象是引用类型,每个对象都是不同的,因此合集实际为两个队列未去重的合并队列(即 Concat);使用指定比较器时,由于比较器对于图形名和大小做出了比较,于是将图形名和大小一致的图形视为重复,便只保留其中一个:
LEI图形 [ ] TuXings1 =
[
new LEI图形 { 形状 = "方形" , 大小 = 23.5m },
new LEI图形 { 形状 = "方形" , 大小 = 23.5m },
new LEI图形 { 形状 = "圆形" , 大小 = 13.5m },
];
LEI图形 [ ] TuXings2 =
[
new LEI图形 { 形状 = "正方形" , 大小 = 23.5m },
new LEI图形 { 形状 = "方形" , 大小 = 23.5m },
new LEI图形 { 形状 = "椭圆形" , 大小 = 16.5m },
];
IEnumerable < LEI图形 > TuXing合集 = TuXings1 . Union ( TuXings2 );
FF显示队列 ( "未使用比较器的合集:" , TuXing合集 );
TuXing合集 = TuXings1 . Union ( TuXings2 , new LEI图形比较器 ( ) );
FF显示队列 ( "使用比较器的合集:" , TuXing合集 );
static void FF显示队列<T> ( string 说明 , IEnumerable<T> 队列 )
{
Console . WriteLine ( "==================== " + 说明 + " ====================" );
Console . WriteLine ( string . Join ( ',' , 队列 ) );
}
public class LEI图形
{
public string? 形状 { get; set; }
public decimal 大小 { get; set; }
public override string ToString ( )
{
return $"{形状}:{大小}";
}
}
public class LEI图形比较器 : IEqualityComparer < LEI图形 >
{
// 如果两个图形的形状和大小都一致,即被认为是相同的
public bool Equals ( LEI图形? x , LEI图形? y )
{
// 首先检查两个对象是否引用相同的数据
if ( object . ReferenceEquals ( x , y ) ) return true;
// 任意一个值为 null,返回 false
if ( x is null || y is null )
return false;
// 通过对图形的形状和大小的检查
return x . 形状 == y . 形状 && x . 大小 == y . 大小;
}
public int GetHashCode ( [DisallowNull] LEI图形 obj )
{
// null 返回 0
if ( obj is null ) return 0;
// 当形状不是 null,获取形状的 HashCode
int TX哈希 = obj . 形状 == null ? 0 : obj . 形状 . GetHashCode ( );
// 获取大小的 HashCode
int TX大小哈希 = obj . 大小 . GetHashCode ( );
// 计算整个图形的 HashCode
return TX哈希 ^ TX大小哈希;
}
}备注
此方法通过延迟执行来实现。其直接返回值是一个对象,该对象存储执行该操作所需的所有信息。只有当直接调用对象的 GetEnumerator 方法,或在 C# 中使用 foreach、在 Visual Basic 中使用 For Each 对对象进行枚举时,此方法所表示的查询才会执行。
如果 比较器 为 null,则使用默认的相等比较器 Default 来比较值。
当此方法返回的对象被枚举时,Union 会按该顺序枚举 队列1 和 队列2,并生成每个尚未生成的元素。
Concat 方法与 Union 方法的不同之处在于,Concat 方法会返回输入序列中的所有元素(包括重复项),而 Union 方法仅返回唯一值。
UnionBy
根据指定的键选择器函数(可选的键比较器函数)生成两个队列的并集。
重载
| 重载 | 注解 |
|---|---|
| UnionBy < T源 , T键 > ( IEnumerable < T源 > , IEnumerable < T源 > , Func < T源 , T键 > ) | 使用默认比较器生成两个队列的并集 |
| UnionBy < T源 , T键 > ( IEnumerable < T源 > , IEnumerable < T源 > , Func < T源 , T键 > , IEqualityComparer < T键 > ) | 使用指定比较器生成两个队列的并集 |
public static System . Collections . Generic . IEnumerable < T源 > UnionBy < T源 , T键 > ( this System . Collections . Generic . IEnumerable < T源 > 队列1 , System . Collections . Generic . IEnumerable < T源 > 队列2 , Func < T源 , T键 > 键选择器 );
public static System . Collections . Generic . IEnumerable < T源 > UnionBy < T源 , T键 > ( this System . Collections . Generic . IEnumerable < T源 > 队列1 , System . Collections . Generic . IEnumerable < T源 > 队列2 , Func < T源 , T键 > 键选择器 , System . Collections . Generic . IEqualityComparer < T键 >? 键比较器 );参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T源 | T | 欲求合集的两个队列的元素类型,即结果的元素类型 |
| T键 | T | 键选择器生成的键值的元素类型 |
| 队列1 队列2 | IEnumerable < T源 > | 欲求合集的两个队列 |
| 键选择器 | Func < T源 , T键 > | 提取每个元素的键的函数 |
| 键比较器 | IEqualityComparer < T键 >? | 对于 队列1 和 队列2 中的元素生成的键值是否相等的比较器。null 或未指定则为默认比较器 |
返回值
| 类型 | 注解 |
|---|---|
| IEnumerable < T源 > | 一个包含 队列1 和 队列2 中的所有元素且按照 键选择器 和 键比较器 去重的队列 |
异常
| 异常 | 注解 |
|---|---|
| ArgumentNullException | 队列1 或 队列2 为 null |
示例
以下示例展示了你要出门干活的装备准备情况(由于合集主体是包里的,所以包外如果有 ID 为 101 的任意物品,都会被排除在整装待发之外):
( int ID , string 名称 , decimal 价格 ) [ ] WP包里的=
{
( 101 , "笔记本" , 4500m ),
( 102 , "鼠标" , 36m ),
( 103 , "键盘" , 25m ),
};
( int ID , string 名称 , decimal 价格 ) [ ] WP包外的=
{
( 102 , "鼠标" , 36m ),
( 104 , "显示器" , 1600m ),
( 101 , "笔记本" , 4500m ),
};
var ZuHe整体 =
WP包里的 . UnionBy ( WP包外的 , wp => wp . ID );
FF显示队列 ( "整装待发的物品列表:" , ZuHe整体 );
static void FF显示队列<T> ( string 说明 , IEnumerable<T> 队列 )
{
Console . WriteLine ( "==================== " + 说明 + " ====================" );
Console . WriteLine ( string . Join ( ',' , 队列 ) );
}以下示例展示了使用使用指定键比较器的对 string 队列的合集,默认比较器时,由于 string 对象区分大小写的,每个不同写法的对象(即使是一个词)都是不同的,因此合集实际仅将两个队列中写法一致的词汇去重;使用指定比较器(不区分大小写)时,将仅存在大小写区别的词汇去重:
string [ ] Zfc1 = [ "apple" , "orange" , "Black" , "White" , "BAG" , "zoom" ];
string [ ] Zfc2 = [ "appLe" , "orAnge" , "Black" , "White" , "BaG" , "Zoom" ];
var zfc默认 = Zfc1 . UnionBy ( Zfc2 , x => x );
FF显示队列 ( "使用默认比较器的字符串合集:" , zfc默认 );
var zfc忽略大小写 = Zfc1 . UnionBy ( Zfc2 , x => x , StringComparer . OrdinalIgnoreCase );
FF显示队列 ( "使用忽略大小写比较器的字符串合集:" , zfc忽略大小写 );
static void FF显示队列<T> ( string 说明 , IEnumerable<T> 队列 )
{
Console . WriteLine ( "==================== " + 说明 + " ====================" );
Console . WriteLine ( string . Join ( ',' , 队列 ) );
}备注
此方法通过延迟执行来实现。其直接返回值是一个对象,该对象存储执行该操作所需的所有信息。只有当直接调用对象的 GetEnumerator 方法,或在 C# 中使用 foreach、在 Visual Basic 中使用 For Each 对对象进行枚举时,此方法所表示的查询才会执行。
如果 比较器 为 null,则使用默认的相等比较器 Default 来比较值。
当此方法返回的对象被枚举时,UnionBy 会按该顺序枚举 队列1 和 队列2,并生成每个尚未生成的元素。
Where
根据条件委托(谓词)筛选队列。
重载
| 重载 | 注解 |
|---|---|
| Where < T源 > ( IEnumerable < T源 > , Func < T源 , Boolean > ) | 根据条件委托筛选队列 |
| Where < T源 > ( IEnumerable < T源 > , Func < T源 , 索引 , Boolean > ) | 根据条件委托(其逻辑会使用每个元素的索引)筛选队列 |
public static System . Collections . Generic . IEnumerable < T源 > Where < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , bool > 条件委托 );
public static System . Collections . Generic . IEnumerable < T源 > Where < T源 > ( this System . Collections . Generic . IEnumerable < T源 > 源 , Func < T源 , int 索引 , bool > 条件委托 );参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T源 | T | 源队列的元素类型 |
| 源 | IEnumerable < T源 > | 欲筛选的源队列 |
| 条件委托 | Func < T源 , bool > Func < T源 , int 索引 , bool > | 用于测试每个 源 中的元素是否筛选出来的条件(可以包含元素的索引) |
返回值
| 类型 | 注解 |
|---|---|
| IEnumerable < T源 > | 源 队列中满足 条件委托 的所有元素组成的队列 |
异常
| 异常 | 注解 |
|---|---|
| ArgumentNullException | 源 或 条件委托 为 null |
示例
以下示例展示了不带 索引 参数的 条件委托,以选取 int 队列中所有大于等于 10 的元素:
Random SJS = new ( );
List < int > Zhss = [ ];
for ( int i = 0 ; i < 10 ; i ++ )
{
Zhss . Add ( SJS . Next ( 21 ) );
}
FF显示队列 ( "初始队列:" , Zhss );
IEnumerable < int > Zhss大于10 = Zhss . Where ( x => x >= 10 ) ;
FF显示队列 ( "大于 10 的队列:" , Zhss大于10 );
static void FF显示队列<T> ( string 说明 , IEnumerable<T> 队列 )
{
Console . WriteLine ( "==================== " + 说明 + " ====================" );
Console . WriteLine ( string . Join ( ',' , 队列 ) );
}以下示例继承自上述示例,但只选取 int 队列中索引 3 ~ 6 之间的大于等于 10 的元素: IEnumerable < int > Zhss3到6之间大于10 = Zhss . Where ( ( x , sy ) => x >= 10 && sy >=3 && sy <= 6 ) ;
备注
此方法通过延迟执行来实现。其直接返回值是一个对象,该对象存储执行操作所需的所有信息。只有当通过直接调用对象的 GetEnumerator 方法,或在 C# 中使用 foreach、在 Visual Basic 中使用 For Each 对该对象进行枚举时,此方法所表示的查询才会执行。
条件委托 的第一个参数表示要测试的元素。可选的第二个参数表示该元素在 源 中的从零开始的索引。
Zip
配对指定的队列的相应元素。
重载
| 重载 | 注解 |
|---|---|
| Zip < T1 , T2 > ( IEnumerable < T1 > , IEnumerable < T2 > ) | 配对两个队列的相应元素 |
| Zip < T1 , T2 , T3 > ( IEnumerable < T1 > , IEnumerable < T2 > , IEnumerable < T3 > ) | 配对三个队列的相应元素 |
| Zip < T1 , T2 , T结果 > ( IEnumerable < T1 > , IEnumerable < T2 > , Func < T1 , T2 , T结果 > ) | 以指定函数,将两个队列的相应元素配对生成结果队列 |
public static System . Collections . Generic . IEnumerable < ( T1 首 , T2 次 ) > Zip < T1 , T2 > ( this System . Collections . Generic . IEnumerable < T1 > 首 , System . Collections . Generic . IEnumerable < T2 > 次 );
public static System . Collections . Generic . IEnumerable < ( T1 首 , T2 次 , T3 三 ) > Zip < T1 , T2 , T3 > ( this System . Collections . Generic . IEnumerable < T1 > 首 , System . Collections . Generic . IEnumerable < T2 > 次 , System . Collections . Generic . IEnumerable < T3 > 三 );
public static System . Collections . Generic . IEnumerable < T结果 > Zip < T1 , T2 , T结果 > ( this System . Collections . Generic . IEnumerable < T1 > 首 , System . Collections . Generic . IEnumerable < T2 > 次 , Func < T1 , T2 , T结果 > 结果选择器 );参数
| 参数 | 类型 | 注解 |
|---|---|---|
| T1、T2、T3 | T | 欲配对其元素的队列的元素类型 |
| 首、次、三 | IEnumerable < T1 > IEnumerable < T2 > IEnumerable < T3 > | 欲配对其元素的队列 |
| T结果 | T | 结果选择器生成的队列的元素类型 |
| 结果选择器 | Func < T1 , T2 , T结果 > | 以两个队列的相应元素生成结果队列的元素的函数 |
返回值
| 类型 | 注解 |
|---|---|
| IEnumerable < ValueTuple < T1 , T2 > > IEnumerable < ValueTuple < T1 , T2 , T3 > > | 将两个或三个队列的元素配对的队列 |
| IEnumerable < T结果 > | 结果选择器生成的队列 |
异常
| 异常 | 注解 |
|---|---|
| ArgumentNullException | 当使用 结果选择器 时,首 或 次 为 null |
示例
以下示例展示了 Zip 两个不同类型的队列:
Random SJS = new ( );
List < int > Zhss = [ ];
List < double > Sjds = [ ];
for ( int i = 0 ; i < 10 ; i ++ )
{
int z = SJS .Next ( 21 );
Zhss . Add ( z );
Sjds . Add ( ( double ) z / 3 );
}
FF显示队列 ( "初始整数队列:" , Zhss );
FF显示队列 ( "初始浮点数队列:" , Sjds );
IEnumerable < ValueTuple < int , double > > ZhsHeSjd = Zhss . Zip ( Sjds );
FF显示队列 ( "连接后的整数及其三分之一:" , ZhsHeSjd );
static void FF显示队列 < T > ( string 说明 , IEnumerable < T > 队列 )
{
Console . WriteLine ( "==================== " + 说明 + " ====================" );
Console . WriteLine ( string . Join ( ',' , 队列 ) );
}以下示例拓展了上述示例,链接三个队列的元素:
Random SJS = new ( );
List < int > Zhss = [ ];
List < double > Sjds三分之一 = [ ];
List < double > Sjds四分之一 = [ ];
for ( int i = 0 ; i < 10 ; i ++ )
{
int z = SJS .Next ( 21 );
Zhss . Add ( z );
Sjds三分之一 . Add ( ( double ) z / 3 );
Sjds四分之一 . Add ( ( double ) z / 4 );
}
FF显示队列 ( "初始整数队列:" , Zhss );
FF显示队列 ( "初始浮点数(1/3)队列:" , Sjds三分之一 );
FF显示队列 ( "初始浮点数(1/4)队列:" , Sjds四分之一 );
IEnumerable < ValueTuple < int , double , double > > ZhsHeSjd = Zhss . Zip ( Sjds三分之一 , Sjds四分之一 );
FF显示队列 ( "连接后的整数及其三分之一和四分之一:" , ZhsHeSjd );
static void FF显示队列 < T > ( string 说明 , IEnumerable < T > 队列 )
{
Console . WriteLine ( "==================== " + 说明 + " ====================" );
Console . WriteLine ( string . Join ( ',' , 队列 ) );
}Zip 并没有提供配对更多队列的重载(至多 3 个),下列示例使用了 结果选择器,并对结果重构以配对第四个队列:
Random SJS = new ( );
List < int > Zhss = [ ];
List < double > Sjds二分之一 = [ ];
List < double > Sjds三分之一 = [ ];
List < double > Sjds四分之一 = [ ];
for ( int i = 0 ; i < 10 ; i ++ )
{
int z = SJS .Next ( 21 );
Zhss . Add ( z );
Sjds二分之一 . Add ( ( double ) z / 2 );
Sjds三分之一 . Add ( ( double ) z / 3 );
Sjds四分之一 . Add ( ( double ) z / 4 );
}
FF显示队列 ( "初始整数队列:" , Zhss );
FF显示队列 ( "初始浮点数(1/2)队列:" , Sjds二分之一 );
FF显示队列 ( "初始浮点数(1/3)队列:" , Sjds三分之一 );
FF显示队列 ( "初始浮点数(1/4)队列:" , Sjds四分之一 );
var ZhsHeSjd = Zhss . Zip ( Sjds二分之一 , ( a , b ) => ( a , b ) ) . Zip ( Sjds三分之一 , ( ab , c ) => ( ab . a , ab . b , c ) ) . Zip ( Sjds四分之一 , ( abc , d ) => ( abc . a , abc . b , abc . c , d ) );
FF显示队列 ( "连接后的整数及其二分之一、三分之一和四分之一:" , ZhsHeSjd );
static void FF显示队列 < T > ( string 说明 , IEnumerable < T > 队列 )
{
Console . WriteLine ( "==================== " + 说明 + " ====================" );
Console . WriteLine ( string . Join ( ',' , 队列 ) );
}注解
此方法是使用延迟执行实现的。 即时返回值是一个对象,用于存储执行操作所需的所有信息。除非通过直接调用其 GetEnumerator 方法或在 C# 中使用 foreach 或在 Visual Basic 中使用 For Each 来枚举对象,否则不会执行此方法表示的查询。
该方法将 首 的每个元素与 次(或包括 三)中具有相同索引的元素合并。如果队列的 Count 不相同,该方法将合并队列,直到某个队列没有元素为止。例如,如果 首 有三个元素,次 有四个元素,则结果队列将只有三个元素。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用。你还可以使用@来通知其他用户。