优雅的方式来结合多个元素的集合?
说我有任意数量的集合,每个集合包含相同types的对象(例如, 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中应该有办法做到,但也许不行。
我想你可能正在寻找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
删除重复项。