经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C# » 查看文章
[C#] LINQ之SelectMany
来源:cnblogs  作者:cnc  时间:2018/10/25 9:37:17  对本文有异议

声明:本文为www.cnc6.cn原创,转载时请注明出处,谢谢!

一、第一种用法:

  1. public static IEnumerable<TResult> SelectMany<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TResult>> selector);

官方释义:将序列的每个元素投影到 IEnumerable<TResult> 并将结果序列合并为一个序列。

废话不多说,直接Post上代码:

1,编写Person类:

  1. class Person
  2. {
  3. public string Name { set; get; }
  4. public int Age { set; get; }
  5. public string Gender { set; get; }
  6. public Dog[] Dogs { set; get; }
  7. }

2,编写Dog类:

  1. public class Dog
  2. {
  3. public string Name { set; get; }
  4. }

请注意:在Person类里有一个Dog数组,用于存储实例化Person类所拥有的所有Dog集合,这里就是SelectMany的关键。

3、编写客户端试验代码:

  1. List<Person> personList = new List<Person>
  2. {
  3. new Person
  4. {
  5. Name = "P1", Age = 18, Gender = "Male",
  6. Gogs = new Dog[]
  7. {
  8. new Dog { Name = "D1" },
  9. new Dog { Name = "D2" }
  10. }
  11. },
  12. new Person
  13. {
  14. Name = "P2", Age = 19, Gender = "Male",
  15. Gogs = new Dog[]
  16. {
  17. new Dog { Name = "D3" }
  18. }
  19. },
  20. new Person
  21. {
  22. Name = "P3", Age = 17,Gender = "Female",
  23. Dogs = new Dog[]
  24. {
  25. new Dog { Name = "D4" },
  26. new Dog { Name = "D5" },
  27. new Dog { Name = "D6" }
  28. }
  29. }
  30. };
  31. var dogs = personList.SelectMany(p => p.Dogs);
  32. foreach (var dog in dogs)
  33. {
  34. Console.WriteLine(dog.Name);
  35. }

在这里我们定义了由Person构成的List列表,并使用集合及对象初始化器初始化了一些数据。

在这里,SelectMany的作用就是:将personList集合对象的每个元素(每个Person实例对象,如名为“P1”,“P2”,“P3”)

映射到每个Person类对应的Dog集合(如名为“P1”对应Dog名为D1及D2的Dog集合),

并将每个Person类对应Dog的集合重新组合成一个大的Dog集合。

因此,以上将会输出以下结果:

实际以上的SelectMany对应的LINQ语句为:

  1. var dogs = from p in personList
  2. from d in p.Dogs
  3. select d;

我们可以将其代替试试就知道结果。

2、第二种用法:

  1. public static IEnumerable<TResult> SelectMany<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, int, IEnumerable<TResult>> selector);

官方释义:将序列的每个元素投影到 IEnumerable<TResult>,并将结果序列合并为一个序列。每个源元素的索引用于该元素的投影表。

其实,就是比第一种使用方法多一个索引而已,该索引是从0开始,针对的是TSource指定类型的集合,最大索引值为TSource个数-1。

我们将第一种客户端试验代码中的

  1. var dogs = personList.SelectMany(p => p.Dogs);

修改为

  1. var dogs = personList.SelectMany((p, i) =>
  2. p.Dogs.Select( d=>
  3. {
  4. d.Name = $"{i},{d.Name}";
  5. return d;
  6. }));

以上方法仅仅是把索引值加到Dog类的Name属性上。

由以上可以看到,共有3个Person,因此,索引值最大为2,每个Person类有多少个Dog(如名为P1的Person类,共有2个Dog),

对应的索引就被使用了多少次数(如名为P1的Person类,索引0被使用了2次),

输出结果如下:

三、第三种用法:

  1. public static IEnumerable<TResult> SelectMany<TSource, TCollection, TResult>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TCollection>> collectionSelector, Func<TSource, TCollection, TResult> resultSelector);

官方释义:将序列的每个元素投影到 IEnumerable<TCollection>,并将结果序列合并为一个序列,并对其中每个元素调用结果选择器函数。

这个用法,跟第一种用法相比,就是可以对已合成一个大集合的每个元素调用结果选择器,返回自己想要的集合类型。

编写客户端试验代码:

  1. List<Person> personList = new List<Person>
  2. {
  3. new Person
  4. {
  5. Name = "P1", Age = 18, Gender = "Male",
  6. Gogs = new Dog[]
  7. {
  8. new Dog { Name = "D1" },
  9. new Dog { Name = "D2" }
  10. }
  11. },
  12. new Person
  13. {
  14. Name = "P2", Age = 19, Gender = "Male",
  15. Gogs = new Dog[]
  16. {
  17. new Dog { Name = "D3" }
  18. }
  19. },
  20. new Person
  21. {
  22. Name = "P3", Age = 17,Gender = "Female",
  23. Gogs = new Dog[]
  24. {
  25. new Dog { Name = "D4" },
  26. new Dog { Name = "D5" },
  27. new Dog { Name = "D6" }
  28. }
  29. }
  30. };
  31. var results = personList.SelectMany(p => p.Dogs, (p, d) => new { PersonName = p.Name, DogName = d.Name });
  32. foreach (var result in results)
  33. {
  34. Console.WriteLine($"{result.PersonName},{result.DogName}");
  35. }

关于SelectMany的用法说明如下:

第一个参数:p=>p.Dogs,p指定是想要处理的每个Person对象,而p.Dogs则是想让p实例映射的Dog集合;

第二个参数:(p, d) => new { PersonName = p.Name, DogName = d.Name },p与d分别指定是映射后(其实有点类似数据库的CROSS JOIN)的person实例与dog实例,

如名为P1的Person类,其Dogs名为D1及D2,那么p与d就是:P1/D1,P1/D2(指定是名称),处理其他Person类也是如此。而new { PersonName = p.Name, DogName = d.Name }则是返回的一个由自己定义的匿名类型。

结果输出如下:

实际以上的SelectMany对应的LINQ语句为:

  1. var results = from p in personList
  2. from d in p.Dogs
  3. select new { PersonName = p.Name, DogName = d.Name };

四、第四种用法:

  1. public static IEnumerable<TResult> SelectMany<TSource, TCollection, TResult>(this IEnumerable<TSource> source, Func<TSource, int, IEnumerable<TCollection>> collectionSelector, Func<TSource, TCollection, TResult> resultSelector);

官方释义:将序列的每个元素投影到 IEnumerable<TCollection>,并将结果序列合并为一个序列,并对其中每个元素调用结果选择器函数。每个源元素的索引用于该元素的中间投影表。

其实,就是比第三种使用方法多一个索引而已,该索引是从0开始,针对的是TSource指定类型的集合,最大索引值为TSource个数-1。

我们将第三种客户端试验代码中的

  1. var results = personList.SelectMany(p => p.Dogs, (p, d) => new { PersonName = p.Name, DogName = d.Name });

修改为

  1. var results = personList.SelectMany((p,i) =>
  2. {
  3. for(int j=0;j<p.Dogs.Length;j++)
  4. {
  5. p.Dogs[j].Name = $"{i}-{p.Dogs[j].Name}";
  6. }
  7. return p.Dogs;
  8. }, (p, d) => new { PersonName = p.Name, DogName = d.Name });

以上方法仅仅是把索引值加到Dog类的Name属性上,并将Dog集合返回。

由以上可以看到,共有3个Person,因此,索引值最大为2,每个Person类有多少个Dog(如名为P1的Person类,共有2个Dog),

对应的索引就被使用了多少次数(如名为P1的Person类,索引0被使用了2次),

输出结果如下:

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号