假设我有任意数量的集合,每个集合都包含相同类型的对象(例如 List foo
和 List bar
)。如果这些集合本身位于一个集合中(例如,List>
类型),我可以使用 SelectMany
将它们全部合并到一个集合中。
但是,如果这些集合尚未位于同一个集合中,我的印象是我必须编写这样的方法:
public static IEnumerable<T> Combine<T>(params ICollection<T>[] toCombine)
{
return toCombine.SelectMany(x => x);
}
然后我会这样调用:
var combined = Combine(foo, bar);
是否有一种干净、优雅的方式来组合(任意数量的)集合无需编写像上面的 Combine
这样的实用方法?看起来很简单,应该有一种方法可以在 LINQ 中实现这一点,但也许不是。
Say I have an arbitrary number of collections, each containing objects of the same type (for example, List<int> foo
and List<int> bar
). If these collections were themselves in a collection (e.g., of type List<List<int>>
, I could use SelectMany
to combine them all into one collection.
However, if these collections are not already in the same collection, it's my impression that I'd have to write a method like this:
public static IEnumerable<T> Combine<T>(params ICollection<T>[] toCombine)
{
return toCombine.SelectMany(x => x);
}
Which I'd then call like this:
var combined = Combine(foo, bar);
Is there a clean, elegant way to combine (any number of) collections without having to write a utility method like Combine
above? It seems simple enough that there should be a way to do it in LINQ, but perhaps not.
发布评论
评论(11)
我想您可能正在寻找 LINQ 的
.Concat()
?或者,
.Union()
将删除重复的元素。I think you might be looking for LINQ's
.Concat()
?Alternatively,
.Union()
will remove duplicate elements.对我来说,当我有多个大序列需要连接时,
Concat
作为扩展方法在我的代码中并不是很优雅。这只是一个代码缩进/格式问题,而且是非常个人化的问题。当然,它看起来像这样:
读起来不太可读:
或者看起来像:
或任何您喜欢的格式。随着更复杂的连接,事情会变得更糟。我与上述风格的认知不一致的原因是第一个序列位于 Concat 方法之外,而后续序列位于内部。我更喜欢直接调用静态 Concat 方法,而不是扩展样式:
对于更多数量的序列连接,我使用与 OP 中相同的静态方法:
所以我可以写:
看起来更好。考虑到使用
Concat
调用我的序列看起来更干净,我必须编写的额外的(否则是多余的)类名对我来说不是问题。在 C# 6 中这不是什么问题。您可以只写:希望我们在 C# 中拥有列表串联运算符,例如:
这样更干净。
To me
Concat
as an extension method is not very elegant in my code when I have multiple large sequences to concat. This is merely a codde indentation/formatting problem and something very personal.Sure it looks good like this:
Not so readable when it reads like:
Or when it looks like:
or whatever your preferred formatting is. Things get worse with more complex concats. The reason for my sort of cognitive dissonance with the above style is that the first sequence lie outside of the
Concat
method whereas the subsequent sequences lie inside. I rather prefer to call the staticConcat
method directly and not the extension style:For more number of concats of sequences I carry the same static method as in OP:
So I can write:
Looks better. The extra, otherwise redundant, class name I have to write is not a problem for me considering my sequences look cleaner with the
Concat
call. It's less of a problem in C# 6. You can just write:Wished we had list concatenation operators in C#, something like:
Much cleaner that way.
对于当您确实有一个集合的集合时的情况,即
List
,>
Enumerable.Aggregate
是一个更将所有列表合并为一个的优雅方式:For the case when you do have a collection of collections, i.e. a
List<List<T>>
,Enumerable.Aggregate
is a more elegant way to combine all lists into one:使用
Enumerable.Concat
如下所示:Use
Enumerable.Concat
like so:您始终可以将 Aggregate 与 Concat 结合使用...
You could always use Aggregate combined with Concat...
使用
Enumerable.Concat
:Use
Enumerable.Concat
:我看到的唯一方法是使用
Concat()
但你应该决定什么是更好的:
或者
一点为什么
Concat()
将是一个更好的选择是,对于另一个开发人员来说,这会更加明显。更具可读性和简单性。The only way I see is to use
Concat()
But you should decide what is better:
or
One point why
Concat()
will be a better choice is that it will be more obvious for another developer. More readable and simple.您可以按如下方式使用 Union:
不过,这会删除相同的元素,因此如果您有这些元素,您可能需要使用
Concat
来代替。You can use Union as follows:
This will remove identical elements, though, so if you have those, you might want to use
Concat
, instead.对于任何
IEnumerable> ,您所需要的就是这个lists
:这会将
lists
中的所有项目组合成一个IEnumerable
(包含重复项)。使用Union
而不是Concat
来删除重复项,如其他答案中所述。All you need is this, for any
IEnumerable<IEnumerable<T>> lists
:This will combine all the items in
lists
into oneIEnumerable<T>
(with duplicates). UseUnion
instead ofConcat
to remove duplicates, as noted in the other answers.使用集合初始值设定项的一些技术 -
假设这些列表:
带有数组初始值设定项的
SelectMany
(对我来说不是那么优雅,但不依赖于任何辅助函数):为 Add 定义一个列表扩展允许
List
中的IEnumerable
初始化器:然后你可以创建一个包含其他元素的新列表,如下所示(它也允许混合单个项目)。
A couple techniques using Collection Initializers --
assuming these lists:
SelectMany
with an array initializer (not really that elegant to me, but doesn't rely on any helper function):Define a list extension for Add which allows
IEnumerable<T>
in theList<T>
initializer:Then you can create a new list containing the elements of the others like this (it also allows single items to be mixed in).
鉴于您从一堆单独的集合开始,我认为您的解决方案相当优雅。您将必须做一些事情来将它们缝合在一起。
从语法上来说,从您的合并方法中创建一个扩展方法会更方便,这将使它可以在任何地方使用。
Given that you're starting with a bunch of separate collections, I think your solution is rather elegant. You're going to have to do something to stitch them together.
It would be more convenient syntactically to make an extension method out of your Combine method, which would make it available anywhere you go.