SelectMany操作符用于根据输入序列中的每一个元素,在输出序列中创建相应的零个或者多个元素,与上一节Select操作符不同,Select操作符会根据输入序列中的每一个元素创建一个对应的输出序列元素,然而SelectMany操作符可以创建多个。
这个可能不太好理解,其实非常的简单,就是SelectMany会将集合中的每个元素按字符或子元素拆成多个元素,比如上一节中例子:
List<People > list = new List<People >();
list.Add(new People() { Name = "李四", Age = 21 });
如果是用Select操作符,var query = list.Select(p = > p.Name ); 那么返回的结果序列query就只包含一个元素,即”李四”,但如果是用SelectMany操作符,var query=list.SelectMany(P= >p.Name),返回的结果序列query会包含两个元素,即“李”,“四”。
示例:
List<List<int > > numbers = new List<List<int > >()
{
new List<int >{1,2,3},
new List<int >{4,5,6},
new List<int >{7,8,9}
};
var result = numbers.SelectMany(collection = > collection);
foreach (int i in result)
{
Console.WriteLine(i);
}
运行效果如下:
但如果源集合的每个元素本身也是一个集合,如下:
List<string[] > list = new List<string[] >()
{
new string[]{"test1", "test2"},
new string[]{"test3", "test4"},
new string[]{"test5", "test6"}
};
var query = list.SelectMany(p = > p);
foreach (var item in query)
{
Console.WriteLine(item);
}
SelectMany操作符会将list中的每个string[]按其每个string元素组成一个大的IEnumerable<string >集合,运行效果如下:
明白其作用后,我们来看SelectMany的原型方法:
SelectMany有四个原型方法,如下:
public static IEnumerable<TResult > SelectMany<TSource, TResult >(this IEnumerable<TSource > source, Func<TSource, IEnumerable<TResult > > selector);
public static IEnumerable<TResult > SelectMany<TSource, TResult >(this IEnumerable<TSource > source, Func<TSource, int, IEnumerable<TResult > > selector);
public static IEnumerable<TResult > SelectMany<TSource, TCollection, TResult >(this IEnumerable<TSource > source, Func<TSource, IEnumerable<TCollection > > collectionSelector, Func<TSource, TCollection, TResult > resultSelector);
public static IEnumerable<TResult > SelectMany<TSource, TCollection, TResult >(this IEnumerable<TSource > source, Func<TSource, int, IEnumerable<TCollection > > collectionSelector, Func<TSource, TCollection, TResult > resultSelector);
第一个方法就是前面讲解的示例,对比第一个方法,第二个方法的委托参数比第一个多了一个int参数,这个int参数就是集合的下标,在之前的章节已经有讲解其作用。
第三个方法对比第一个方法,多了一个委托参数resultSelector,该委托有两个参数,TSource是源集合中的元素,TCollection为第一个委托参数处理后的中间结果集,SelectMany会对源集合中的每个元素调用原委托方法后对其结果再调用resultSelector委托。示例如下,我们将源集合list中new string[]的长度与new string[]中的每个元素组合成一个新的集合并输出:
List<string[] > list = new List<string[] >()
{
new string[]{"test1", "test2"},
new string[]{"test3", "test4"},
new string[]{"test5", "test6"}
};
var query = list.SelectMany(p = > p, (p, result) = > new { p.Length, result })
.Select(
p = > new
{
Leng = p.Length,
Test = p.result
}
);
foreach (var item in query)
{
Console.WriteLine(item);
}
Console.ReadLine();
}
输出效果如下: