C# LINQ详解(一)

2024-08-22 04:48
文章标签 c# 详解 .net netcore linq

本文主要是介绍C# LINQ详解(一),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录 

LINQ 基础 

扩展方法-幕后的工作 

扩展方法列表 

Where and Select 

All 

Average 

Concat 

Contains 

Count 

DefaultIfEmpty 

Distinct 

ElementAt 

Empty 

Except 

First 

FirstOrDefault 

Union 

Intersect 

Last 

LastOrDefault 

LongCount 

Max 

Min 

OfType 

Range 

Repeat 

Reverse 

Single 

Skip 

SkipWhile 

Sum 

ThenBy 

ToArray 

ToDictionary 

ToList 

Zip 

LINQ基础介绍 

         .NET,任何数据结构都是由在mscorlib.dllSystem.Collections.Generic命名空间下的Ienumerable<T>接口得到的. 映射可以访问所有的定义在System.Core.dllSystem.Linq命名空间下的枚举类.这个枚举类是定义在System.Core.dllSystem.Linq命名空间下的一个静态非可继承类.这个枚举类的定义如下: 

.class public abstract auto ansi sealed beforefieldinit System.Linq.Enumerable extends [mscorlib]System.Object 

这个静态枚举类是对Ienumerable<T>接口中不同扩展方法的一个封装.例如下面的例子: 

复制代码
public static bool Contains<TSource>( this IEnumerable<TSource> source, TSource value) { /* code removed*/} public static int Count<TSource>( this IEnumerable<TSource> source)  { /* code removed*/} public static IEnumerable<TSource> Distinct<TSource>( this IEnumerable<TSource> source, IEqualityComparer<TSource> comparer)  { /* code removed*/} // and many more 
复制代码

扩展方法介绍 

Where and Select 

Where Select是两个定义在Ienumerable<TSource>接口中非常重要的方法.它们的定义如下: 

public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, int, bool> predicate) 

所以任何来源于Ienumerable<TSource>接口的数据结构都能访问这个方法,例如List<T>.List<T>类实现了Ienumerable<T>接口,它的定义如下: 

public class List<T> : IList<T>, ICollection<T>, IEnumerable<T>, IList, ICollection, Ienumerable 

那么来让我们看一个关于WhereSelect的例子. 

复制代码
 1 using System; 2 3 using System.Collections; 4 5 using System.Collections.Generic; 6 7 using System.Linq; 8 9  
10 
11 namespace Chapter_5 
12 
13 { 
14 
15     class Program 
16 
17     { 
18 
19         static void Main(string[] args) 
20 
21         { 
22 
23             IList<string> numbers = new List<string>()  
24 
25             {  
26 
27                 "One", "Two", "Three", "Four",  
28 
29                 "Five", "Six", "Seven"  
30 
31             }; 
32 
33  
34 
35             var numbersLengthThree = 
36 
37                 numbers.Where(x => x.Length == 3).Select(x => x).ToList(); 
38 
39  
40 
41             numbersLengthThree.ForEach(x => Console.WriteLine(x)); 
42 
43         } 
44 
45     } 
46 
47 } 
复制代码

上面的代码会产生一个string类型的列表(列表中是数字)存储在List<string>,上面的程序会找出在这些项中字符总数是3的并且将结果存储到另外一个新的列表中.最后在控制台中打印出这些数字.这个程序输出的结果如下: 

One 

Two 

Six 

让我们做一个研究去找出它是如何工作的.在上面的例子中最重要的代码是numbers.Where(x => x.Length == 3).Select(x => x).ToList().下边的图表会为我们解释整个的执行过程. 

通过上面的图表我们可以知道CLR伴随着MulticastDelegate实例(持有着关于<Main>b_1方法的信息)将数字列表作为输入参数传递到Where方法,其中<Main>b_1创建于匿名函数(x=>x.Length==3).通过Where方法它会返回一个WhereListIterator<string>迭代器的实例,这个实例将会作为输入参数传递到Select子句中,伴随着另外一个MulticastDelegate实例(持有着关于<Main>b_2方法的信息),<Main>b_2通过匿名方法(x=>x)创建。Select方法将根据输入内容实例化相关的迭代器。在这种情况下,它会实例化出WhereSelectListIterator<string,string>迭代器。这个迭代器将作为输入参数传递到ToList()方法中。此方法最终通过循环遍历对原始列表进行处理并得到一个基于过滤条件的新列表。 

 

All 

这个方法确定是否所有元素序列都满足某种条件,如果每一个元素都可以满足设定的特殊条件或者它是空,则方法返回true,否则返回false。方法定义如下: 

public static bool All<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) 

 

这个方法被用在判断是否一个元素序列满足某种条件。序列中的每一个元素都会经过判断。在下面的程序中,我创建了一个包含OneTwoThree等项目的List<string>实例,下面的程序将找出在这个序列中是否包含不少于3个字符的元素。 

复制代码
 1 using System; 
 2 
 3 using System.Collections; 
 4 
 5 using System.Collections.Generic; 
 6 
 7 using System.Linq; 
 8 
 9  
10 
11 namespace Chapter_5 
12 
13 { 
14 
15     class Program 
16 
17     { 
18 
19         static void Main(string[] args) 
20 
21         { 
22 
23             IList<string> numbers = new List<string>()  
24 
25             {  
26 
27                 "One", "Two", "Three", "Four",  
28 
29                 "Five", "Six", "Seven"  
30 
31             }; 
32 
33  
34 
35             if (numbers.All<string>(x => x.Length >= 3)) 
36 
37                 Console.WriteLine("All numbers have at least three characters."); 
38 
39         } 
40 
41     } 
42 
43 } 
复制代码

 

上面的程序将会输出:All numbers have at least three characters. 

因为All方法都将匹配序列中的元素对于指定的条件是否有效。它的工作原理如下图: 

图像

从上面的图表我们可以知道CLR会通过数字列表作为输入参数传递到All()中,伴随着MulticasDelegate类的实例(这个实例通过匿名函数(x=>x.Length>=3)来创建)。在All()方法中,CLR将通过指定的条件找出序列中的每一个元素是否满足条件。 

 

Any 

这个方法确定序列中的元素是否存在或者满足某种特定的条件。方法定义如下: 

public static bool Any<TSource>(this IEnumerable<TSource> source) public static bool Any<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) 

 

上面的两个方法将会执行下面的情况: 

第一种重载会找出元素序列是否包含元素,第二种重载将会找出序列中是否有满足条件的元素。我写了一个小程序去解释这两种方法工作的细节。 

复制代码
 1 using System; 
 2 
 3 using System.Collections; 
 4 
 5 using System.Collections.Generic; 
 6 
 7 using System.Linq; 
 8 
 9  
10 
11 namespace Chapter_5 
12 
13 { 
14 
15     class Program 
16 
17     { 
18 
19         static void Main(string[] args) 
20 
21         { 
22 
23             IList<string> numbers = new List<string>()  
24 
25             {  
26 
27                 "One", "Two", "Three", "Four",  
28 
29                 "Five", "Six", "Seven"  
30 
31             }; 
32 
33  
34 
35             if (numbers.Any<string>()) 
36 
37                 Console.WriteLine("The sequence contains item."); 
38 
39  
40 
41             if (numbers.Any<string>(x => x.Length >= 3)) 
42 
43                 Console.WriteLine("The sequence contains at least a item which has three or more characters"); 
44 
45  
46 
47         } 
48 
49     } 
50 
51 } 
复制代码

 

上面的程序将会做如下输出: 

The sequence contains item. 

The sequence contains at least a item which has three or more characters 

Press any key to continue . . . 

 

Average 

Average方法会计算在序列中的数字的平均值。这个方法的定义如下: 

public static double Average(this IEnumerable<int> source) public static decimal Average<TSource>(this IEnumerable<TSource> source, Func<TSource, decimal> selector) 

 

下面是一个关于Average方法的列子: 

复制代码
 1 using System; 
 2 
 3 using System.Collections; 
 4 
 5 using System.Collections.Generic; 
 6 
 7 using System.Linq; 
 8 
 9  
10 
11 namespace Chapter_5 
12 
13 { 
14 
15     class Program 
16 
17     { 
18 
19         static void Main(string[] args) 
20 
21         { 
22 
23             IList<int> numbers = new List<int>()  
24 
25             {  
26 
27                 1,2,3,4,5,6,7,8,9,10 
28 
29             }; 
30 
31  
32 
33             Console.WriteLine("Average of the numbers :{0}", numbers.Average()); 
34 
35  
36 
37             Console.WriteLine("Average of the original numbers x2 :{0}",  
38 
39                               numbers.Average((x => x * 2))); 
40 
41  
42 
43         } 
44 
45     } 
46 
47 } 
复制代码

 

上面的程序将会做如下输出: 

Average of the numbers :5.5 

Average of the original numbers x2 :11 

Press any key to continue . . . 

 

Concat 

这个方法的作用是连接(拼接)两个序列.这个方法通过"延迟执行"(deferred execution)来执行.它的返回值是包含需要执行特定操作所有信息的迭代器类型的一种实例.C#,对象在调用它的GetEnumerator方法或者使用foreach语句时才会执行Concat方法. 

Concat<TSource>(Ienumerable<TSource>,Ienumerable<TSource>)方法不同于Union(),因为Concat<TSource>(Ienumerable<TSource>,Ienumerable<TSource>)方法会返回序列中所有的原始元素,Union则返回序列中不重复(独一无二)的元素.方法定义如下: 

public static IEnumerable<TSource> Concat<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second) 

 

下面的程序将告诉我们怎样使用Concat方法. 

复制代码
 1 using System; 
 2 
 3 using System.Collections; 
 4 
 5 using System.Collections.Generic; 
 6 
 7 using System.Linq; 
 8 
 9  
10 
11 namespace Chapter_5 
12 
13 { 
14 
15     class Program 
16 
17     { 
18 
19         static void Main(string[] args) 
20 
21         { 
22 
23             IList<int> listOne = new List<int>()  
24 
25             {  
26 
27                 1,2,3,4,5 
28 
29             }; 
30 
31  
32 
33             IList<int> listTwo = new List<int>()  
34 
35             {  
36 
37                 6,7,8,9,10 
38 
39             }; 
40 
41  
42 
43             var result = listOne.Concat(listTwo).ToList(); 
44 
45             result.ForEach(x=> Console.WriteLine(x)); 
46 
47  
48 
49  
50 
51         } 
52 
53     } 
54 
55 } 
复制代码

 

上面的程序将会做如下输出: 

1 

2 

3 

4 

5 

6 

7 

8 

9 

10 

Press any key to continue . . . 

Concat方法的工作原理如下图所示: 

图像

从上图我们可以知道CLR通过将listOnelistTwo作为输入参数传递到Concat方法中,并且从Concat方法中返回一个ConcatIterator实例作为输出参数给这个方法的调用者.虽然这将通过延迟执行模式来执行,但是ToList()方法也会通过listOnelistTwoConcatIterator类的执行逻辑来开始处理并得到最终的集合。 

 

Contains 

这个方法用来判断在一个序列(集合)中是否存在一个特殊的元素.这个方法有两种重载方式,第一种是通过默认的比较器来判断序列(集合)中是否有特殊的元素,另外一种是通过自定义IEqualityComparer<T>来确定序列(集合)中是否有特殊的元素.它们的方法定义如下: 

public static bool Contains<TSource>(this IEnumerable<TSource> source, TSource value) public static bool Contains<TSource>(this IEnumerable<TSource> source, TSource value, IEqualityComparer<TSource> comparer) 

 

这个方法将会查找在集合中是否有一个特殊的值存在.为了解释这个方法我写了一个小程序: 

复制代码
 1 using System; 
 2 
 3 using System.Collections; 
 4 
 5 using System.Collections.Generic; 
 6 
 7  
 8 
 9 namespace Chapter_5 
10 
11 { 
12 
13     class Program 
14 
15     { 
16 
17         static void Main(string[] args) 
18 
19         { 
20 
21             IList<int> listOne = new List<int>()  
22 
23             {  
24 
25                 1,2,3,4,5 
26 
27             }; 
28 
29  
30 
31             var resultAsTrue = listOne.Contains(2); 
32 
33             var resultAsFalse = listOne.Contains(200); 
34 
35             Console.WriteLine("{0}\n{1}", resultAsTrue, resultAsFalse); 
36 
37         } 
38 
39     } 
40 
41 } 
复制代码

 

上面的程序将会做如下输出: 

True 

False 

Press any key to continue . . 


因此,在上述程序中当编译器找到Contains方法的第一种重载方式,它会执行如下步骤:CLR会通过Contains方法在集合中查找一个特定的值.这种查找会有两个方向,一种是如果输入参数是一个空值(null value),(CLR)会在集合中循环遍历是空值的项,如果其中一项是空值,就返回true,反之返回false.另一种情况是当不是空值的时候,CLR会对集合中的项依次进行比较,根据匹配值返回一个布尔类型作为应答. 

Contains方法的一个近似代码如下所示: 

复制代码
 1 public bool Contains(T item) 
 2 
 3 { 
 4 
 5     if (item == null) 
 6 
 7     { 
 8 
 9         for (int j = 0; j < this._size; j++) 
10 
11         { 
12 
13             if (this._items[j] == null) 
14 
15             { 
16 
17                 return true; 
18 
19             } 
20 
21         } 
22 
23         return false; 
24 
25     } 
26 
27  
28 
29     EqualityComparer<T> comparer = EqualityComparer<T>.Default; 
30 
31     for (int i = 0; i < this._size; i++) 
32 
33     { 
34 
35         if (comparer.Equals(this._items[i], item)) 
36 
37         { 
38 
39             return true; 
40 
41         } 
42 
43     } 
44 
45     return false; 
46 
47 } 
复制代码

 

 

Count 

Count方法将返回序列(集合)中元素的个数.这个方法的定义如下: 

public static int Count<TSource>(this IEnumerable<TSource> source) public static int Count<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) 

 

上面的两个重载方法将会做如下操作.第一种重载直接返回序列(集合)中元素的个数,第二种重载返回一个数字,表示在序列(集合)中有多少元素满足指定的条件。 

Count方法将找出在集合中一共有多少个项.例如在下面的程序中我创建了一个string类型的集合,我用Count()来找出在这个集合里有多少项以及有多少项是超过3个字符的. 

复制代码
 1 using System; 
 2 
 3 using System.Collections; 
 4 
 5 using System.Collections.Generic; 
 6 
 7 using System.Linq; 
 8 
 9  
10 
11 namespace Chapter_5 
12 
13 { 
14 
15     class Program 
16 
17     { 
18 
19         static void Main(string[] args) 
20 
21         { 
22 
23             IList<string> listOne = new List<string>()  
24 
25             {  
26 
27                 "One","Two","Three" 
28 
29             }; 
30 
31  
32 
33             var result = listOne.Count(); 
34 
35  
36 
37             var fourOrMoreCharacters = listOne.Count(item => item.Length > 3); 
38 
39             Console.WriteLine("{0}\n{1}", result,fourOrMoreCharacters); 
40 
41         } 
42 
43     } 
44 
45 } 
复制代码

 

上面的程序会做如下输出: 

3 

1 

Press any key to continue . . . 

在这个例子中我使用了Count方法的两种重载方式. 

 

DefaultIfEmpty 

这个方法会返回一个IEnumerable<T>类型的元素或者当序列(集合)为空事放回一个默认的单例集合.这个方法的定义如下: 

public static IEnumerable<TSource> DefaultIfEmpty<TSource>(this IEnumerable<TSource> source) public static IEnumerable<TSource> DefaultIfEmpty<TSource>(this IEnumerable<TSource> source, TSource defaultValue) 

 

上面的两种重载方式将会这样做:第一种重载将返回指定的元素序列(集合)或者当序列(集合)为空的情况下返回一个单例集合中类型参数的默认值.第二种重载将返回指定的元素序列(集合)或者在序列(集合)为空的情况下返回一个单例集合中特定的值. 

这个方法可以用在一个不含有任何项的列表(集合)并且如果我们在这个列表中使用这个方法,它将返回缺省值.让我们看看在下面的程序中如何使用DefaultIfEmpty方法. 

复制代码
 1 using System.Collections; 
 2 
 3 using System.Collections.Generic; 
 4 
 5 using System.Linq; 
 6 
 7  
 8 
 9 namespace Chapter_5 
10 
11 { 
12 
13     class Program 
14 
15     { 
16 
17         static void Main(string[] args) 
18 
19         { 
20 
21  
22 
23             IList<Person> persons = new List<Person>(); 
24 
25             IList<int> numbers = new List<int>(); 
26 
27             IList<string> names = new List<string>(); 
28 
29  
30 
31             var defaultPersons = persons.DefaultIfEmpty(); 
32 
33  
34 
35             var defaultNumbers = numbers.DefaultIfEmpty().ToList(); 
36 
37  
38 
39             var defaultNames = names.DefaultIfEmpty(); 
40 
41         } 
42 
43     } 
44 
45  
46 
47     class Person 
48 
49     { 
50 
51         public string Name 
52 
53         { 
54 
55             get; 
56 
57             set; 
58 
59         } 
60 
61  
62 
63         public string Address 
64 
65         { 
66 
67             get; 
68 
69             set; 
70 
71         } 
72 
73  
74 
75         public int Age 
76 
77         { 
78 
79             get; 
80 
81             set; 
82 
83         } 
84 
85     } 
86 
87 } 
复制代码

 

在上面的程序中我声明了personnumbersnames三个集合,分别是Personintstring类型。这三个集合不包含任何项,它们的Count属性将会返回0.当我使用DefaultIfEmpty方法在任意一个集合上时,CLR会做如下步骤去执行。首先CLR会复制一份集合到DefaultIfEmpty方法,从这个方法中,CLR会返回一个包含defaultvalue和源值的DefaultIfEmptyIterator<TSource>迭代器的实例。The defaultvalue property will contain the default value of the type of list and source will be the original list. CLR会把DefaultIfEmptyItereator传递到ToList()方法中,它会通过把DefaultIfEmptyItereator作为输入参数调用集合类,在这个类中,CLR将遍历原始列表(集合)并处理结果。 

图像

DefaultIfEmptyTterator相近的代码如下: 

复制代码
 1 private static IEnumerable<TSource> DefaultIfEmptyIterator<TSource>(IEnumerable<TSource> source, TSource defaultValue) 
 2 
 3 { 
 4 
 5     using (IEnumerator<TSource> iteratorVariable0 = source.GetEnumerator()) 
 6 
 7     { 
 8 
 9         if (iteratorVariable0.MoveNext()) 
10 
11             do 
12 
13             { 
14 
15                 yield return iteratorVariable0.Current; 
16 
17             } 
18 
19             while (iteratorVariable0.MoveNext()); 
20 
21         else 
22 
23             yield return defaultValue; 
24 
25     } 
26 
27 } 
复制代码

 

 

Distinct 

这个方法将从序列(集合)中返回去重复(Distinct)元素。这个方法的定义是: 

public static IEnumerable<TSource> Distinct<TSource>(this IEnumerable<TSource> source) public static IEnumerable<TSource> Distinct<TSource>(this IEnumerable<TSource> source, IEqualityComparer<TSource> comparer) 

 

这个方法有两种重载方式,第一种重载通过默认比较器从序列(集合)中返回去重复的元素。第二种重载通过使用自定义IEquaityComparer<T>从序列(集合)中返回去重复的元素。 

这个方法将会从列表(集合)中返回同一的项。如果我们有一个包含重复项的列表(集合),那么这个方法将会过滤掉重复的项并返回一个只包含单一值的新列表(集合)。我们来看下面的程序。 

复制代码
 1 using System; 
 2 
 3 using System.Collections; 
 4 
 5 using System.Collections.Generic; 
 6 
 7 using System.Linq; 
 8 
 9  
10 
11 namespace Chapter_5 
12 
13 { 
14 
15     class Program 
16 
17     { 
18 
19         static void Main(string[] args) 
20 
21         { 
22 
23             IList<int> numbers = new List<int>() 
24 
25             { 
26 
27                 1,1,1,2,2,2,3,3,3 
28 
29             }; 
30 
31  
32 
33             var distinctedNumbers = numbers.Distinct().ToList(); 
34 
35             distinctedNumbers.ForEach(x=>Console.WriteLine(x)); 
36 
37         } 
38 
39     } 
40 
41 } 
复制代码

 

程序会输出: 

1 

2 

3 

Press any key to continue . . . 

当上面程序运行的时候,它会只产生{123},下面的图表描述了Distinct方法如何工作。 

图像

要执行Distinct方法,CLR会这样做:第一,CLR会拷贝一份原始列表(集合)并作为输入参数传递到Distinct方法并且在内部调用Distinct<TSource>方法,这将返回一个DistinctIterator<TSource>类的实例,但是这个迭代器因为“延迟执行”不会执行(要执行DistinctIterator迭代器,我们需要调用ToList()方法或做ForEach)。第二,从ToList()方法,CLR会通过在第一步中创建的DistinctIterator作为输入参数调用列表(集合)类。这个列表(集合)类将会循环遍历DistinctIterator的实例。在DistinctIterator中的迭代逻辑会创建一个新的Set<TSource>实例并循环遍历原始列表然后将重复的项添加到先前创建的Set<TSource>实例中。内部的这个Set<TSource>类会使用AddFind方法从给定的序列(集合)中把项添加到内部的数组中直到数组里没有了重复项。这步操作会在CLR到达列表(集合)最后是才会停止并得到一个去重复的列表(集合)。因此,Distinct方法在list中会这样执行: 

复制代码
 1 private static IEnumerable<TSource> DistinctIterator<TSource>( 
 2 
 3     IEnumerable<TSource> source, IEqualityComparer<TSource> comparer) 
 4 
 5 { 
 6 
 7     Set<TSource> iteratorVariable0 = new Set<TSource>(comparer); 
 8 
 9     foreach (TSource iteratorVariable1 in source) 
10 
11     { 
12 
13         if (iteratorVariable0.Add(iteratorVariable1)) 
14 
15         { 
16 
17             yield return iteratorVariable1; 
18 
19         } 
20 
21     } 
22 
23 } 
复制代码

 

 

ElementAt 

在序列(集合),这个方法返回一个特定索引的一个元素.这个方法的定义是: 

public static TSource ElementAt<TSource>(this IEnumerable<TSource> source, int index) public static TSource ElementAtOrDefault<TSource>(this IEnumerable<TSource> source, int index) 

 

在下面的示例中使用了Ienumerable<TSource>ElementAt方法. 

复制代码
 1 using System; 
 2 
 3 using System.Collections.Generic; 
 4 
 5 using System.Linq; 
 6 
 7   
 8 
 9 namespace Chapter_5 
10 
11 { 
12 
13     class Program 
14 
15     { 
16 
17         static void Main(string[] args) 
18 
19         { 
20 
21             IList<string> numbers = new List<string>() 
22 
23             { 
24 
25                 "One","Two","Three" 
26 
27             }; 
28 
29   
30 
31             var elementAt = numbers.ElementAt(1); 
32 
33   
34 
35             Console.WriteLine(elementAt); 
36 
37         } 
38 
39     } 
40 
41 } 
复制代码

 

这个程序创建了一个包含OneTwoThree元素的数字集合。在这个数字列表中我尝试去访问在位置1处的元素并将结果存储到elementAt变量中,然后在控制台输出.这个程序的输出结果是: 

Two 

Press any key to continue . . . 

 

Empty 

Empty返回一个指定类型参数的空Ienumerable<T>. 

方法定义如下: 

public static IEnumerable<TResult> Empty<TResult>() 

 

下面的示例说明了Empty方法的用法. 

复制代码
 1 using System; 
 2 
 3 using System.Linq; 
 4 
 5  
 6 
 7 namespace Chapter_5 
 8 
 9 { 
10 
11     class Program 
12 
13     { 
14 
15         static void Main(string[] args) 
16 
17         { 
18 
19             var emptyList = Enumerable.Empty<int>(); 
20 
21  
22 
23             Console.WriteLine(emptyList.Count()); 
24 
25         } 
26 
27     } 
28 
29 } 
复制代码

 

在上面的代码中我用Empty()方法创建了一个int类型的空集合,程序会做如下输出: 

0 

Press any key to continue . . . 

 

Except 

Except方法可以用在从一个集合中删除一个项集合.它放回一个由两个序列产生的集合差.方法定义是: 

1 public static IEnumerable<TSource> Except<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second) 
2 
3 public static IEnumerable<TSource> Except<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer) 

 

第一种重载是利用默认的比较器生成两个序列的集合差.第二种重载是利用IEQualityComparer<T>生成两个序列的集合差.Except方法可以用在从一个集合中删除一个项集合.比如,我有个由{1,2,3,4,5,6,7}组成的集合A和由{1,2,3}组成的集合B,A 除了(except) B 将会输出{4,5,6,7},下面的程序说明了Except的用法. 

复制代码
 1 using System.Collections; 
 2 
 3 using System.Collections.Generic; 
 4 
 5 using System.Linq; 
 6 
 7 using System; 
 8 
 9  
10 
11 namespace Chapter_5 
12 
13 { 
14 
15     class Program 
16 
17     { 
18 
19         static void Main(string[] args) 
20 
21         { 
22 
23             IList<int> firstNumbers = new List<int>() 
24 
25             { 
26 
27                 1,2,3,4,5,6,7 
28 
29             }; 
30 
31             IList<int> secondNumbers = new List<int>() 
32 
33             { 
34 
35                 1,2,3 
36 
37             }; 
38 
39  
40 
41             var result = firstNumbers.Except(secondNumbers).ToList(); 
42 
43             result.ForEach(x => Console.WriteLine(x)); 
44 
45         } 
46 
47     } 
48 
49 } 
复制代码

 

程序将会输出: 

4 

5 

6 

7 

Press any key to continue . . . 

当上面的程序执行的时候会产生{4,5,6,7},下面的图表展示了Except方法是如何工作的. 

图像

 

 

First 

这个方法会返回序列中的第一个元素.方法定义是: 

public static TSource First<TSource>(this IEnumerable<TSource> source) public static TSource First<TSource>(this IEnumerable<TSource> source,Func<TSource, bool> predicate) 

 

第一种重载将找出在序列中的第一个元素.第二种重载将根据条件找出第一个元素.我写了一个小程序去解释First方法的执行步骤. 

复制代码
 1 using System.Collections; 
 2 
 3 using System.Collections.Generic; 
 4 
 5 using System.Linq; 
 6 
 7 using System; 
 8 
 9  
10 
11 namespace Chapter_5 
12 
13 { 
14 
15     class Program 
16 
17     { 
18 
19         static void Main(string[] args) 
20 
21         { 
22 
23             IList<int> numbers = new List<int>() 
24 
25             { 
26 
27                 1,2,3,4,5,6,7 
28 
29             }; 
30 
31  
32 
33             var firstItem = numbers.First(); 
34 
35             var firstItemBasedOnConditions = numbers.First(item => item > 3); 
36 
37  
38 
39             Console.WriteLine("{0}\n{1}", 
40 
41                 firstItem, 
42 
43                 firstItemBasedOnConditions 
44 
45                 ); 
46 
47         } 
48 
49     } 
50 
51 } 
复制代码

 

程序将会输出: 

1 

4 

Press any key to continue . . . 

 

FirstOrDefault 

它返回序列中第一个元素或者当没有元素未被找到时放回默认值.这个方法是FirstDefault的综合,这里不再叙述. 

 

Union 

这个方法将会Union(并集)两个序列(集合).例如,我们有两个集合,A={1,2,3,4,5,6,7}B={5,6,7,8,9},并集AB则返回{1,2,3,4,5,6,7,8,9}..NET,它将连接两个列表(集合)并生成一个新列表(集合). 

public static IEnumerable<TSource> Union<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second) public static IEnumerable<TSource> Union<TSource>(this IEnumerable<TSource> first,IEnumerable<TSource> second, IEqualityComparer<TSource> comparer) 

 

下面的程序说明了Union的用法. 

复制代码
 1 using System; 
 2 
 3 using System.Collections; 
 4 
 5 using System.Collections.Generic; 
 6 
 7 using System.Linq; 
 8 
 9  
10 
11 namespace Chapter_5 
12 
13 { 
14 
15     class Program 
16 
17     { 
18 
19         static void Main(string[] args) 
20 
21         { 
22 
23             IList<int> firstList = new List<int>()  
24 
25             {  
26 
27                 1,2,3,4 
28 
29             }; 
30 
31  
32 
33             IList<int> secondList = new List<int>()  
34 
35             {  
36 
37                7,9,3,4,5,6,7 
38 
39             }; 
40 
41  
42 
43             var result = firstList.Union(secondList); 
44 
45             result.ToList().ForEach(x => Console.WriteLine(x)); 
46 
47         } 
48 
49     } 
50 
51 } 
复制代码

 

程序将会输出: 

1 

2 

3 

4 

7 

9 

5 

6 

Press any key to continue . . . 

 

 

Intersect 

它将产生两个序列的交集.方法定义是: 

复制代码
public static IEnumerable<TSource> Intersect<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second) public static IEnumerable<TSource> Intersect<TSource>(this IEnumerable<TSource> first,  Enumerable<TSource> second,IEqualityComparer<TSource> comparer) 
复制代码

 

第一种重载将会利用默认平等比较器来创建两个序列的交集,第二种重载是利用IEqualityComparet<T>比较器去比较值然后产生两个序列的交集.它产生两个序列的交集.这个交集将会包含在两个列表中相同的元素.例如,如果我们有一个A列表{1,2,3,4,5}B列表{4,5},取两者交集之后就会生成{4,5}. 

图像

看下面的程序 

复制代码
 1 using System; 
 2 
 3 using System.Collections.Generic; 
 4 
 5 using System.Linq; 
 6 
 7   
 8 
 9 namespace Chapter_5 
10 
11 { 
12 
13     class Program 
14 
15     { 
16 
17         static void Main(string[] args) 
18 
19         { 
20 
21             IList<int> listA = new List<int>() { 1, 2, 3, 4, 5 }; 
22 
23             IList<int> listB = new List<int>() { 4, 5 }; 
24 
25   
26 
27             var intersectResult = listA.Intersect(listB); 
28 
29   
30 
31             intersectResult.ToList().ForEach(x => Console.Write("{0}\t",x)); 
32 
33             Console.WriteLine(); 
34 
35         } 
36 
37     } 
38 
39 } 
复制代码

 

程序会输出: 

4       5 

Press any key to continue . . . 

 

 

Last 

它返回序列中最后一个元素.方法定义是: 

public static TSource Last<TSource>(this IEnumerable<TSource> source) public static TSource Last<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) 

 

第一种重载将会找出在序列中最后一个元素,第二种重载将根据条件找出最后一个元素.我写了一个程序去解释这个方法如何使用: 

复制代码
 1 using System; 
 2 
 3 using System.Collections.Generic; 
 4 
 5 using System.Linq; 
 6 
 7 using System.Text; 
 8 
 9 using System.Threading.Tasks; 
10 
11  
12 
13 namespace Chapter1 
14 
15 { 
16 
17     class Program 
18 
19     { 
20 
21         static void Main(string[] args) 
22 
23         { 
24 
25             IList<int> numbers = new List<int>() 
26 
27             { 
28 
29                 1,2,3,4,5,6,7 
30 
31             }; 
32 
33  
34 
35             var lastItem = numbers.Last(); 
36 
37  
38 
39             var lastItemBasedOnConditions = numbers.Last(item => item > 3); 
40 
41  
42 
43             Console.WriteLine(lastItem); 
44 
45             Console.WriteLine(lastItemBasedOnConditions); 
46 
47         } 
48 
49     } 
50 
51 } 
复制代码

 

将会输出: 

7 

7 

Press any key to continue . . . 

 

 

LastOrDefault 

它返回序列中最后一个元素或者当没有元素未被找到时放回默认值.这个方法是LastDefault的综合,这里不再叙述. 

 

LongCount 

它会返回一个Int64去表示序列中元素的个数,方法定义是: 

public static long LongCount<TSource>(this IEnumerable<TSource> source) public static long LongCount<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) 

 

第一种重载放回一个Int64,表示在序列中一共有多少个元素.第二种重载是根据条件放回一个Int64,表示在条件范围内一共有多少个元素. 

让我们做一个例子: 

复制代码
 1 using System; 
 2 
 3 using System.Collections; 
 4 
 5 using System.Collections.Generic; 
 6 
 7 using System.Linq; 
 8 
 9  
10 
11 namespace Chapter_5 
12 
13 { 
14 
15     class Program 
16 
17     { 
18 
19         static void Main(string[] args) 
20 
21         { 
22 
23             IList<int> firstList = new List<int>()  
24 
25             {  
26 
27                 1,2,3,4 
28 
29             }; 
30 
31  
32 
33             Console.WriteLine(firstList.LongCount()); 
34 
35         } 
36 
37     } 
38 
39 } 
复制代码
 
       
       
       
       
       
       
       

这篇关于C# LINQ详解(一)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1095288

相关文章

Python标准库之数据压缩和存档的应用详解

《Python标准库之数据压缩和存档的应用详解》在数据处理与存储领域,压缩和存档是提升效率的关键技术,Python标准库提供了一套完整的工具链,下面小编就来和大家简单介绍一下吧... 目录一、核心模块架构与设计哲学二、关键模块深度解析1.tarfile:专业级归档工具2.zipfile:跨平台归档首选3.

idea的终端(Terminal)cmd的命令换成linux的命令详解

《idea的终端(Terminal)cmd的命令换成linux的命令详解》本文介绍IDEA配置Git的步骤:安装Git、修改终端设置并重启IDEA,强调顺序,作为个人经验分享,希望提供参考并支持脚本之... 目录一编程、设置前二、前置条件三、android设置四、设置后总结一、php设置前二、前置条件

python中列表应用和扩展性实用详解

《python中列表应用和扩展性实用详解》文章介绍了Python列表的核心特性:有序数据集合,用[]定义,元素类型可不同,支持迭代、循环、切片,可执行增删改查、排序、推导式及嵌套操作,是常用的数据处理... 目录1、列表定义2、格式3、列表是可迭代对象4、列表的常见操作总结1、列表定义是处理一组有序项目的

python使用try函数详解

《python使用try函数详解》Pythontry语句用于异常处理,支持捕获特定/多种异常、else/final子句确保资源释放,结合with语句自动清理,可自定义异常及嵌套结构,灵活应对错误场景... 目录try 函数的基本语法捕获特定异常捕获多个异常使用 else 子句使用 finally 子句捕获所

C++11范围for初始化列表auto decltype详解

《C++11范围for初始化列表autodecltype详解》C++11引入auto类型推导、decltype类型推断、统一列表初始化、范围for循环及智能指针,提升代码简洁性、类型安全与资源管理效... 目录C++11新特性1. 自动类型推导auto1.1 基本语法2. decltype3. 列表初始化3

C#中lock关键字的使用小结

《C#中lock关键字的使用小结》在C#中,lock关键字用于确保当一个线程位于给定实例的代码块中时,其他线程无法访问同一实例的该代码块,下面就来介绍一下lock关键字的使用... 目录使用方式工作原理注意事项示例代码为什么不能lock值类型在C#中,lock关键字用于确保当一个线程位于给定实例的代码块中时

SQL Server 中的 WITH (NOLOCK) 示例详解

《SQLServer中的WITH(NOLOCK)示例详解》SQLServer中的WITH(NOLOCK)是一种表提示,等同于READUNCOMMITTED隔离级别,允许查询在不获取共享锁的情... 目录SQL Server 中的 WITH (NOLOCK) 详解一、WITH (NOLOCK) 的本质二、工作

C# $字符串插值的使用

《C#$字符串插值的使用》本文介绍了C#中的字符串插值功能,详细介绍了使用$符号的实现方式,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧... 目录$ 字符使用方式创建内插字符串包含不同的数据类型控制内插表达式的格式控制内插表达式的对齐方式内插表达式中使用转义序列内插表达式中使用

C#中的Converter的具体应用

《C#中的Converter的具体应用》C#中的Converter提供了一种灵活的类型转换机制,本文详细介绍了Converter的基本概念、使用场景,具有一定的参考价值,感兴趣的可以了解一下... 目录Converter的基本概念1. Converter委托2. 使用场景布尔型转换示例示例1:简单的字符串到

springboot自定义注解RateLimiter限流注解技术文档详解

《springboot自定义注解RateLimiter限流注解技术文档详解》文章介绍了限流技术的概念、作用及实现方式,通过SpringAOP拦截方法、缓存存储计数器,结合注解、枚举、异常类等核心组件,... 目录什么是限流系统架构核心组件详解1. 限流注解 (@RateLimiter)2. 限流类型枚举 (