假设我有任意数量的集合,每个集合包含相同类型的对象(例如,List<int> foo
和List<int> bar
)。如果这些集合本身位于集合中(例如,类型为List<List<int>>
),我可以使用SelectMany
将它们全部合并到一个集合中。
但是,如果这些集合不在同一个集合中,那么我的印象是我必须编写这样的方法:
public static IEnumerable<T> Combine<T>(params ICollection<T>[] toCombine)
{
return toCombine.SelectMany(x => x);
}
然后我会这样打电话:
var combined = Combine(foo, bar);
是否有一种干净,优雅的方式来组合(任意数量)集合而无需编写上面的Combine
实用程序方法?看起来很简单,应该有一种方法可以在LINQ中完成它,但也许不是。
答案 0 :(得分:81)
我想您可能正在寻找LINQ的.Concat()
?
var combined = foo.Concat(bar).Concat(foobar).Concat(...);
或者,.Union()
将删除重复的元素。
答案 1 :(得分:21)
对我来说Concat
作为扩展方法在我的代码中不是很优雅,因为我有多个大序列要连接。这只是一个codde缩进/格式化问题,而且非常个人化。
当然看起来很不错:
var list = list1.Concat(list2).Concat(list3);
如下所示不太可读:
var list = list1.Select(x = > x)
.Concat(list2.Where(x => true)
.Concat(list3.OrderBy(x => x));
或者看起来像:
return Normalize(list1, a, b)
.Concat(Normalize(list2, b, c))
.Concat(Normalize(list3, c, d));
或任何您喜欢的格式。随着更复杂的concats,事情变得更糟。我的种认知失调与上述风格的原因是第一个序列位于Concat
方法之外,而后续序列位于其中。我更喜欢直接调用静态Concat
方法而不是扩展样式:
var list = Enumerable.Concat(list1.Select(x => x),
list2.Where(x => true));
对于更多序列的concats,我使用与OP中相同的静态方法:
public static IEnumerable<T> Concat<T>(params IEnumerable<T>[] sequences)
{
return sequences.SelectMany(x => x);
}
所以我可以写:
return EnumerableEx.Concat
(
list1.Select(x = > x),
list2.Where(x => true),
list3.OrderBy(x => x)
);
看起来更好。考虑到Concat
调用我的序列看起来更干净,我必须编写的额外的,多余的类名称对我来说不是问题。这不是 C#6 中的问题。你可以写:
return Concat(list1.Select(x = > x),
list2.Where(x => true),
list3.OrderBy(x => x));
希望我们在C#中使用列表连接运算符,类似于:
list1 @ list2 // F#
list1 ++ list2 // Scala
那种方式更干净。
答案 2 :(得分:20)
对于做有一个集合集合的情况,即List<List<T>>
,Enumerable.Aggregate
是将所有列表合并为一个更优雅的方式:
var combined = lists.Aggregate((acc, list) => { return acc.Concat(list); });
答案 3 :(得分:14)
像这样使用Enumerable.Concat
:
var combined = foo.Concat(bar).Concat(baz)....;
答案 4 :(得分:7)
var query = foo.Concat(bar);
答案 5 :(得分:7)
您总是可以将Aggregate与Concat结合使用......
-9
答案 6 :(得分:6)
我看到的唯一方法是使用Concat()
var foo = new List<int> { 1, 2, 3 };
var bar = new List<int> { 4, 5, 6 };
var tor = new List<int> { 7, 8, 9 };
var result = foo.Concat(bar).Concat(tor);
但你应该决定什么是更好的:
var result = Combine(foo, bar, tor);
或
var result = foo.Concat(bar).Concat(tor);
有一点为什么Concat()
将是一个更好的选择,对于其他开发者来说更明显。更具可读性和简单性。
答案 7 :(得分:2)
您可以按如下方式使用Union:
var combined=foo.Union(bar).Union(baz)...
这会删除相同的元素,所以如果你有这些元素,你可能想要使用Concat
。
答案 8 :(得分:1)
鉴于您从一堆独立的系列开始,我认为您的解决方案相当优雅。你将不得不做某事来将它们拼接在一起。
使用Combine方法制作扩展方法在语法上会更方便,这样可以随时随地使用。
答案 9 :(得分:1)
使用集合初始化程序的几种技术-
假设这些列表:
var list1 = new List<int> { 1, 2, 3 };
var list2 = new List<int> { 4, 5, 6 };
SelectMany
和一个数组初始值设定项(对我来说不是很优雅,但不依赖任何辅助函数):
var combined = new []{ list1, list2 }.SelectMany(x => x);
为“添加”定义列表扩展名,该扩展名允许IEnumerable<T>
initializer中的List<T>
:
public static class ListExtensions
{
public static void Add<T>(this List<T> list, IEnumerable<T> items) => list.AddRange(items);
}
然后,您可以创建一个包含其他元素的新列表,如下所示(它还允许将单个项目混入其中)。
var combined = new List<int> { list1, list2, 7, 8 };
答案 10 :(得分:0)
对于任何IEnumerable<IEnumerable<T>> lists
:
var combined = lists.Aggregate((l1, l2) => l1.Concat(l2));
这会将lists
中的所有项目合并为一个IEnumerable<T>
(带有重复项)。使用Union
代替Concat
删除重复项,如其他答案中所述。