我想知道如何使用
SelectMany()
。这似乎需要很多争论,从我自己的研究中我注意到 SelectMany()
可能是所有其他选择操作的“父亲”。
Select much 允许您从查询源中选择一个 IEnumerable
您可以运行以下示例来演示 Select 和 SelectMany 之间的差异:
//set up some data for our example
var tuple1 = new { Name = "Tuple1", Values = new int [] { 1, 2, 3 } };
var tuple2 = new { Name = "Tuple2", Values = new int [] { 4, 5, 6 } };
var tuple3 = new { Name = "Tuple3", Values = new int [] { 7, 8, 9 } };
//put the tuples into a collection
var tuples = new [] { tuple1, tuple2, tuple3 };
//"tupleValues" is an IEnumerable<IEnumerable<int>> that contains { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }
var tupleValues = tuples.Select(t => t.Values);
//"tupleSelectManyValues" is an IEnumerable<int> that contains { 1, 2, 3, 4, 5, 6, 7, 8, 9 }
var tupleSelectManyValues = tuples.SelectMany(t => t.Values);
通过使用 SelectMany,您可以更轻松地查询子集合中的值。
SelectMany
有几个重载。其中之一允许您在遍历层次结构时跟踪父母和孩子之间的任何关系。
示例:假设您有以下结构:
League -> Teams -> Player
您可以轻松返回玩家的扁平集合。但是,您可能会丢失有关玩家所属团队的任何参考信息。
幸运的是,有用于此目的的超载:
var teamsAndTheirLeagues =
from helper in leagues.SelectMany
( l => l.Teams,
( league, team ) => new { league, team } )
where helper.team.Players.Count > 2
&& helper.league.Teams.Count < 10
select new
{
LeagueID = helper.league.ID,
Team = helper.team
};
前面的例子取自Dan的IK博客:
http://blogs.interknowlogy.com/2008/10/10/use-linqs-selectmany-method-to-flatten-collections/
我强烈推荐你看一下。
SelectMany 基本上是扁平化和处理分层数据,有两种主要形式
(出于示例目的,请参阅此初始代码)
class TestObj
{
public string Name { get; set; }
public List<string> Items { get; set; }
}
var hierarchicalCollection = new List<TestObj>();
hierarchicalCollection.Add(new TestObj()
{Items = new List<string>()
{"testObj1-Item1", "testObj1-Item2"}, Name="t1"});
hierarchicalCollection.Add(new TestObj()
{Items = new List<string>()
{"testObj2-Item1", "testObj2-Item2"}, Name="t2"});
选项 1)从集合的集合中创建一个集合(本质上是扁平化分层数据)
IEnumerable<string> flattenedCollection =
hierarchicalCollection.SelectMany(t => t.Items);
结果是:
"testObj1-Item1"
"testObj1-Item2"
"testObj2-Item1"
"testObj2-Item2"
选项 2)从集合的集合中创建一个集合,然后通过对原始父集合的引用来处理新集合的每个项目
IEnumerable<string> flattenedModifiedCollection =
hierarchicalCollection.SelectMany
(t => t.Items, (t, i) => t.Name + " : " + i);
结果是:
"t1 : testObj1-Item1"
"t1 : testObj1-Item2"
"t2 : testObj2-Item1"
"t2 : testObj2-Item2"
上述每种用法都有一个变体,其中正在处理的项目的索引可用于转换函数。
我在所有时间都使用这个扩展来深入了解层次结构。
当扩展变得有点混乱时,另一种很酷的方法是使用正式的 LINQ 方式,例如:
var vehicles = from cust in context.Customers
from fleet in cust.Fleets
from v in fleet.Vehicles
select v;
这相当于:
var vehicles = context.Customers.SelectMany(c => c.Fleets).SelectMany(f => f.Vehicles);
添加 where 子句和连接等时可能会有点冗长。 希望这有帮助!
我在 LINQ 中使用 SelectMany 获得了一些乐趣。以下链接描述了在 LINQ select 子句中返回 IEnumerable,该子句返回序列的序列,并使用 SelectMany 将其展平为简单序列。 “使用 Let、Yield return 和 Selectmany 的 Linq to XML”。 它不仅仅是一个 SelectMany 用例,而且是从 LINQ 中的单个输入生成多个输出的方法的一部分。
这是另一个(VB.NET)使用示例:
'Original list
Dim l() As String = {"/d", "/bc:\Temp\In*;c:\Temp\Out", "/hABC", "/s123"}
'Processed list: will list first 2 characters from each string member.
Dim L1 As IEnumerable(Of String) = l.SelectMany(Function(x As String) {x.Substring(0, 2)})
Dim L2 As List(Of String) = l.SelectMany(Function(x As String) {x.Substring(0, 2)}).ToList
'Will return dictionary like list with keys==2 characters and values the rest from each string member.
Dim L3 As List(Of KeyValuePair(Of String, String)) = l.SelectMany(Function(x As String) {New KeyValuePair(Of String, String)(x.Substring(0, 2), x.Substring(2))}).ToList
这是一个老问题,我想提供一些额外的信息。
如前所述,SelectMany() 有多个重载。其中一个这里没有讨论的是一个有趣的重载,它提供了外部迭代元素的索引(即在 List 的情况下每个列表的索引)。
这个重载可以这样使用:
var result = outerCollection.SelectMany((element, index) => /* projection */);