优雅的方式来结合多个元素的集合?

说我有任意数量的集合,每个集合包含相同types的对象(例如, List<int> fooList<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中应该有办法做到,但也许不行。

我想你可能正在寻找LINQ的.Concat()

 var combined = foo.Concat(bar).Concat(foobar).Concat(...); 

或者, .Union()将删除重复的元素。

使用Enumerable.Concat像这样:

 var combined = foo.Concat(bar).Concat(baz)....; 

对我来说Concat作为扩展方法在我的代码中不是很优雅,当我有多个大序列来连接。 这只是一个缩进/格式化问题,还有一些非常个人化的问题。

当然,看起来像这样:

 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)); 

或者你喜欢的格式是什么。 事情变得更加复杂连接。 我认为与上述风格不一致的原因是第一个序列位于Concat方法之外,而后面的序列位于内部。 我宁愿直接调用静态的Concat方法,而不是扩展风格:

 var list = Enumerable.Concat(list1.Select(x => x), list2.Where(x => true)); 

对于更多数量的连续序列,我使用与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)); 

使用Enumerable.Concact

 var query = foo.Concat(bar); 

我看到的唯一方法是使用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()将是一个更好的select的一点是,对于另一个开发者来说,它会更加明显。 更可读和简单。

Enumerable.Aggregate是正确的“优雅”的方式来做到这一点:

 var all = lists.Aggregate((acc, list) => { return acc.Concat(list); }); 

你可以使用Union如下:

 var combined=foo.Union(bar).Union(baz)... 

这将删除相同的元素,所以如果你有这些元素,你可能想用Concat来代替。

鉴于你从一堆单独的集合开始,我认为你的解决scheme是相当优雅的。 你将不得不做一些缝合在一起的东西

使用Combine方法可以在语法上更方便地使用扩展方法,这将使您可以在任何地方使用它。

你总是可以使用Aggregate和Concat结合…

  var listOfLists = new List<List<int>> { new List<int> {1, 2, 3, 4}, new List<int> {5, 6, 7, 8}, new List<int> {9, 10} }; IEnumerable<int> combined = new List<int>(); combined = listOfLists.Aggregate(combined, (current, list) => current.Concat(list)).ToList(); 

所有你需要的是,对于任何IEnumerable<IEnumerable<T>> lists

 var combined = lists.Aggregate((l1, l2) => l1.Concat(l2)); 

这将把lists所有项目合并为一个IEnumerable<T> (带有重复项)。 如其他答案中所述,使用Union而不是Concat删除重复项。