[C#] LINQ之SelectMany
声明:本文为www.cnc6.cn原创,转载时请注明出处,谢谢!
一、第一种用法:
public static IEnumerable<TResult> SelectMany<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TResult>> selector);
官方释义:将序列的每个元素投影到 IEnumerable<TResult> 并将结果序列合并为一个序列。
废话不多说,直接Post上代码:
1,编写Person类:
class Person
{
public string Name { set; get; }
public int Age { set; get; }
public string Gender { set; get; }
public Dog[] Dogs { set; get; }
}
2,编写Dog类:
public class Dog
{
public string Name { set; get; }
}
请注意:在Person类里有一个Dog数组,用于存储实例化Person类所拥有的所有Dog集合,这里就是SelectMany的关键。
3、编写客户端试验代码:
List<Person> personList = new List<Person>
{
new Person
{
Name = "P1", Age = , Gender = "Male",
Gogs = new Dog[]
{
new Dog { Name = "D1" },
new Dog { Name = "D2" }
}
},
new Person
{
Name = "P2", Age = , Gender = "Male",
Gogs = new Dog[]
{
new Dog { Name = "D3" }
}
},
new Person
{
Name = "P3", Age = ,Gender = "Female",
Dogs = new Dog[]
{
new Dog { Name = "D4" },
new Dog { Name = "D5" },
new Dog { Name = "D6" }
}
}
};
var dogs = personList.SelectMany(p => p.Dogs);
foreach (var dog in dogs)
{
Console.WriteLine(dog.Name);
}
在这里我们定义了由Person构成的List列表,并使用集合及对象初始化器初始化了一些数据。
在这里,SelectMany的作用就是:将personList集合对象的每个元素(每个Person实例对象,如名为“P1”,“P2”,“P3”)
映射到每个Person类对应的Dog集合(如名为“P1”对应Dog名为D1及D2的Dog集合),
并将每个Person类对应Dog的集合重新组合成一个大的Dog集合。
因此,以上将会输出以下结果:

实际以上的SelectMany对应的LINQ语句为:
var dogs = from p in personList
from d in p.Dogs
select d;
我们可以将其代替试试就知道结果。
2、第二种用法:
public static IEnumerable<TResult> SelectMany<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, int, IEnumerable<TResult>> selector);
官方释义:将序列的每个元素投影到 IEnumerable<TResult>,并将结果序列合并为一个序列。每个源元素的索引用于该元素的投影表。
其实,就是比第一种使用方法多一个索引而已,该索引是从0开始,针对的是TSource指定类型的集合,最大索引值为TSource个数-1。
我们将第一种客户端试验代码中的
var dogs = personList.SelectMany(p => p.Dogs);
修改为
var dogs = personList.SelectMany((p, i) =>
p.Dogs.Select( d=>
{
d.Name = $"{i},{d.Name}";
return d;
}));
以上方法仅仅是把索引值加到Dog类的Name属性上。
由以上可以看到,共有3个Person,因此,索引值最大为2,每个Person类有多少个Dog(如名为P1的Person类,共有2个Dog),
对应的索引就被使用了多少次数(如名为P1的Person类,索引0被使用了2次),
输出结果如下:

三、第三种用法:
public static IEnumerable<TResult> SelectMany<TSource, TCollection, TResult>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TCollection>> collectionSelector, Func<TSource, TCollection, TResult> resultSelector);
官方释义:将序列的每个元素投影到 IEnumerable<TCollection>,并将结果序列合并为一个序列,并对其中每个元素调用结果选择器函数。
这个用法,跟第一种用法相比,就是可以对已合成一个大集合的每个元素调用结果选择器,返回自己想要的集合类型。
编写客户端试验代码:
List<Person> personList = new List<Person>
{
new Person
{
Name = "P1", Age = , Gender = "Male",
Gogs = new Dog[]
{
new Dog { Name = "D1" },
new Dog { Name = "D2" }
}
},
new Person
{
Name = "P2", Age = , Gender = "Male",
Gogs = new Dog[]
{
new Dog { Name = "D3" }
}
},
new Person
{
Name = "P3", Age = ,Gender = "Female",
Gogs = new Dog[]
{
new Dog { Name = "D4" },
new Dog { Name = "D5" },
new Dog { Name = "D6" }
}
}
};
var results = personList.SelectMany(p => p.Dogs, (p, d) => new { PersonName = p.Name, DogName = d.Name });
foreach (var result in results)
{
Console.WriteLine($"{result.PersonName},{result.DogName}");
}
关于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语句为:
var results = from p in personList
from d in p.Dogs
select new { PersonName = p.Name, DogName = d.Name };
四、第四种用法:
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。
我们将第三种客户端试验代码中的
var results = personList.SelectMany(p => p.Dogs, (p, d) => new { PersonName = p.Name, DogName = d.Name });
修改为
var results = personList.SelectMany((p,i) =>
{
for(int j=;j<p.Dogs.Length;j++)
{
p.Dogs[j].Name = $"{i}-{p.Dogs[j].Name}";
}
return p.Dogs;
}, (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次),
输出结果如下:

[C#] LINQ之SelectMany的更多相关文章
- LINQ 之 SelectMany
声明:本文为www.cnc6.cn原创,转载时请注明出处,谢谢! 一.第一种用法: public static IEnumerable<TResult> SelectMany<TSo ...
- [C#] LINQ之SelectMany和GroupJoin
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...
- 记一次使用 SelectMany 的经历
最近在改造一个功能时为了减少循环的层数,于是想着将List列表映射为一个能直接使用颗粒大小的List列表,这样一层循环就可以解决问题. public class ConflictWordIte ...
- Entity Framework 与 面向对象
说要分享,我了个*,写了一半放草稿箱了两个星期都快发霉了,趁着周末写完发出来吧. 文章分为五部分: 基础.类讲述的是用到的一些EF与面向对象的基础: 业务是讲怎么划分设计业务: 设计模式和工作模式讲述 ...
- 并发编程概述--C#并发编程经典实例
优秀软件的一个关键特征就是具有并发性.过去的几十年,我们可以进行并发编程,但是难度很大.以前,并发性软件的编写.调试和维护都很难,这导致很多开发人员为图省事放弃了并发编程.新版.NET 中的程序库和语 ...
- linq里的select和selectmany操作
Select() 和 SelectMany() 的工作都是依据源值生成一个或多个结果值.Select() 为每个源值生成一个结果值.因此,总体结果是一个与源集合具有相同元素数目的集合.与之相反,Sel ...
- linq读书笔记3-操作符之select与selectmany
linq对数据的查询方式的表达形式主要有两种: var demo =from p in pList where p.id=*** select p; var demo =pList.where(p=& ...
- Linq常用List操作总结,ForEach、分页、交并集、去重、SelectMany等
/* 以下围绕Person类实现,Person类只有Name和Age两个属性 一.List<T>排序 1.1 List<T>提供了很多排序方法,sort(),Orderby() ...
- LINQ操作符二:SelectMany
SelectMany操作符提供了将多个from子句组合起来的功能,相当于数据库中的多表连接查询,它将每个对象的结果合并成单个序列. 示例: student类: using System; using ...
随机推荐
- matlab练习程序(局部加权线性回归)
通常我们使用的最小二乘都需要预先设定一个模型,然后通过最小二乘方法解出模型的系数. 而大多数情况是我们是不知道这个模型的,比如这篇博客中z=ax^2+by^2+cxy+dx+ey+f 这样的模型. 局 ...
- LeetCode算法题-First Bad Version(Java实现-三种解法)
这是悦乐书的第200次更新,第210篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第66题(顺位题号是278).您是产品经理,目前领导团队开发新产品.不幸的是,您产品的最 ...
- linux历史命令查找快捷方式
一.回到上次操作的目录# cd -进入上次访问目录 二.历史命令搜索操作快捷键:[Ctrl + r], [Ctrl + p], [Ctrl + n] 在终端中按捉 [Ctrl] 键的同时 [r] ...
- vue-引入外部js文件的方法和常量
1.方法调用 a: js文件(static/js/public.js) //函数的定义 返回上一页 export function goback(laststep) { laststep } b: ...
- J - Abbott's Revenge 搜索 寒假训练
题目 题目大意:这个题目就是大小不超过9*9的迷宫,给你起点终点和起点的方向,让你进行移动移动特别之处是不一定上下左右都可以,只有根据方向确定可以走的方向.思路:需要写一个读入函数,这个需要读入起点, ...
- Thread.currentThread()和this的区别——《Java多线程编程核心技术》
前言:在阅读<Java多线程编程核心技术>过程中,对书中程序代码Thread.currentThread()与this的区别有点混淆,这里记录下来,加深印象与理解. 具体代码如下: pub ...
- Hibernate知识点总结(一)
前言:学习的过程在于不断的总结与思考,这里记下笔者在学习过程中,所遇到的知识点,增加对框架掌握的熟悉程度. 1.环境的搭建 通过maven可以轻松搭建hibernate的环境. <propert ...
- 【FJWC 2019】 森林
[FJWC 2019] 森林 样例输入 0 5 1 0 0 2 样例输出 1 2 3 3 我们发现,答案就是直径加上直径上某个点出发,不经过其他直径上的点的最长链.这里的直径可以是任意一条直径. 首先 ...
- python 代码检测工具
对于我这种习惯了 Java 这种编译型语言,在使用 Python 这种动态语言的时候,发现错误经常只能在执行的时候发现,总感觉有点不放心. 而且有一些错误由于隐藏的比较深,只有特定逻辑才会触发,往往导 ...
- CAS适用场景
转载:http://www.jb51.net/article/86192.htm 下面小编就为大家带来一篇Java并发编程总结——慎用CAS详解.小编觉得挺不错的, 现在就分享给大家,也给大家做个参考 ...