温故知新C# Linq中 Select && SelectMany 使用技巧

Posted dotNET跨平台

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了温故知新C# Linq中 Select && SelectMany 使用技巧相关的知识,希望对你有一定的参考价值。

微信公众号:趣编程ACE
关注可了解更多的.NET日常实战开发技巧,如需源码 后台回复 源码 即可;
如果觉得对你有帮助,欢迎关注

C# Linq中 Select && SelectMany 使用技巧

Select 和 SelectMany 是我们开发中对集合常用的两个扩展方法,今天我就用几个小例子并结合源码形式展示下这两个方法的使用形式。


前文回顾

【温故知新】C# Linq中 Where使用技巧

Select 的基本使用

首先我创建一个Student的类,类的结构如下:

1   public class Student
 2    
 3        public int Id  get; set;   // 学生ID
 4        public string Name  get; set;  // 学生姓名
 5        public List<string> Programing  get; set;  // 学生掌握的 编程语言
 6
 7
 8        // 获取学生集合
 9        public static List<Student> GetStudents()
10        
11            return new List<Student>()
12            
13                new Student
14                 
15                    Id = 1, 
16                    Name ="张三",
17                    Programing = new List<string>
18                    
19                        "C#","Java","JS"
20                    
21                ,
22                new Student
23                
24                    Id=2,
25                    Name ="李四",
26                    Programing=new List<string>
27                    
28                        "C++","C","Node.js"
29                    
30                ,
31                 new Student
32                
33                    Id=3,
34                    Name ="王五",
35                    Programing=new List<string>
36                    
37                        "Sql","C","Node.js"
38                    
39                ,
40                new Student
41                
42                    Id=4,
43                    Name ="赵六",
44                    Programing=new List<string>
45                    
46                        "MVC","C","Node.js"
47                    
48                ,
49            ;
50        
51
52    

然后在Main函数中调用GetStudents方法,并对集合使用Select方法

1// 因为Id是int 类型 将集合里面所有子项的Id组合起来 变成一个新集合
2// 所以返回值是 IEnumerable<int> 类型
3IEnumerable<int> ids = Student.GetStudents().Select(s => s.Id);  
4foreach (var item in ids)
5
6  Console.WriteLine(item); // 输出 1,2,3,4
7

那么对于这个Select方法,內部源码是怎么实现的呢?

1// F12 进入查看源码结构
2// 返回值是 IEnumerable<TResult> 类型
3// 是所有 IEnumerable<TSource> source 类型的扩展方法
4// 一个入参 Func<TSource, TResult> selector 的内置委托 其中 委托入参是TSource 类型,返回值是TResult类型
5public static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector)

手写Select源码实现:

1public static IEnumerable<TResult> SelectExtension<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector)
 2
 3  if(source == null) throw new ArgumentNullException("source");
 4  if(selector == null) throw new ArgumentNullException("selector");
 5
 6  foreach (var item in source)
 7  
 8    yield return selector(item);
 9  
10

SelectMany 的基本使用

1.在上文定义的Student类中,我们要拿到所有人会的编程语言,那么就可以通过SelectMany实现。

1var stus = Student.GetStudents().SelectMany(s => s.Programing);
2foreach (var item in stus)
3
4   Console.WriteLine(item);
5


那么这个方法中SelectMany的作用是什么呢?
SelectMany 将序列(也就是Student的集合)的每个元素投影到IEnumerable上,这样就将其转化为一个IEnumerable类型的数据。也就是说SelectMany 这个方法将一系列结果组合在一起变成一个新的结果。
以下便是SelectMany的一个重载源码实现:

1// 返回值是 IEnumerable<TResult> 类型
 2// 是所有 IEnumerable<TSource> source 类型的扩展方法
 3// 一个入参 Func<TSource, IEnumerable<TResult>> selector 类型的内置委托 
 4// 其中委托函数需要一个Tsource类型的参数,返回值是IEnumerable<TResult>> 类型
 5public static IEnumerable<TResult> SelectManyExtension<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TResult>> selector)
 6
 7  if(source == null) throw new ArgumentNullException("source");
 8  if(selector == null) throw new ArgumentNullException("selector");
 9   return SelectManyExtensionIterator(source, selector);
10
11//SelectManyExtensionIterator 迭代实现
12static IEnumerable<TResult> SelectManyExtensionIterator<TSource, TResult>(IEnumerable<TSource> source,
13Func<TSource, IEnumerable<TResult>> selector)
14
15   foreach (var item in source)
16    
17      foreach (var result in selector(item))
18       
19         yield return result;
20       
21    
22

2.要拿到每个学生姓名及其所会的编程语言?这就可以通过SelectMany方法的另一种重载来实现

1// 其中SelectMany 第一入参是一个内置委托:
 2  //入参为集合的元素类型,返回值是元素的一个集合类型(Student)
 3// 第二个参数也是一个内置委托: 
 4  //入参有两个,第一个为集合元素类型(Student),第二个为前面参数返回值的元素类型
 5  // 其中这个内置委托的返回值是一个TResult 类型,此处代码TResult 为new 出来的匿名类型
 6var stuInfo = Student.GetStudents().SelectMany(s => s.Programing,
 7                (stu, str) => new
 8                
 9                    StudentName = stu.Name,
10                    PragramName = str
11                );
12foreach (var item in stuInfo)
13
14  Console.WriteLine(item.StudentName+"=>"+item.PragramName);
15


那么这个SelectMany的重载源代码是怎么实现的呢?

1public static IEnumerable<TResult> SelectManyExtension2<TSource, TCollection, TResult>(this IEnumerable<TSource> source, 
 2            Func<TSource, IEnumerable<TCollection>> collectionSelector, 
 3            Func<TSource, TCollection, TResult> resultSelector)
 4        
 5            if(source==null) throw new ArgumentNullException("source");
 6            if(collectionSelector == null) throw new ArgumentNullException("collectionSelector");
 7            if(resultSelector == null) throw new ArgumentNullException("resultSelector");
 8
 9            return SelectManyExtensionIterator2<TSource, TCollection, TResult>(source, collectionSelector, resultSelector);
10        
11
12
13        static IEnumerable<TResult> SelectManyExtensionIterator2<TSource, TCollection, TResult> (IEnumerable<TSource> source,
14            Func<TSource, IEnumerable<TCollection>> collectionSelector,
15            Func<TSource, TCollection, TResult> resultSelector)
16        
17            foreach (var item in source)
18            
19                foreach (var collection in collectionSelector(item))
20                
21                    yield return resultSelector(item, collection);
22                
23            
24        

具体演示看上文视频~

以上是关于温故知新C# Linq中 Select && SelectMany 使用技巧的主要内容,如果未能解决你的问题,请参考以下文章

温故知新C# Linq中 Where使用技巧

无法访问 groupBy 数据 Linq C#

等效于 C# LINQ Select 的 Javascript

c# Linq select join on select group by

LINQ:从列表中选择项目(Group By/Select/Sum & Max!)

C# LINQ 详解 From Where Select Group Into OrderBy Let Join