Say I have an arbitrary number of collections, each containing objects of the same type (for example, List
and List
).
You can use Union as follows:
var combined=foo.Union(bar).Union(baz)...
This will remove identical elements, though, so if you have those, you might want to use Concat
, instead.
I think you might be looking for LINQ's .Concat()?
var combined = foo.Concat(bar).Concat(foobar).Concat(...);
Alternatively, .Union()
will remove duplicate elements.
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:
var list = list1.Concat(list2).Concat(list3);
Not so readable when it reads like:
var list = list1.Select(x = > x)
.Concat(list2.Where(x => true)
.Concat(list3.OrderBy(x => x));
Or when it looks like:
return Normalize(list1, a, b)
.Concat(Normalize(list2, b, c))
.Concat(Normalize(list3, c, d));
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 static Concat
method directly and not the extension style:
var list = Enumerable.Concat(list1.Select(x => x),
list2.Where(x => true));
For more number of concats of sequences I carry the same static method as in OP:
public static IEnumerable<T> Concat<T>(params IEnumerable<T>[] sequences)
{
return sequences.SelectMany(x => x);
}
So I can write:
return EnumerableEx.Concat
(
list1.Select(x = > x),
list2.Where(x => true),
list3.OrderBy(x => x)
);
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:
return Concat(list1.Select(x = > x),
list2.Where(x => true),
list3.OrderBy(x => x));
Wished we had list concatenation operators in C#, something like:
list1 @ list2 // F#
list1 ++ list2 // Scala
Much cleaner that way.
All you need is this, for any IEnumerable<IEnumerable<T>> lists
:
var combined = lists.Aggregate((l1, l2) => l1.Concat(l2));
This will combine all the items in lists
into one IEnumerable<T>
(with duplicates). Use Union
instead of Concat
to remove duplicates, as noted in the other answers.
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.
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:
var combined = lists.Aggregate((acc, list) => { return acc.Concat(list); });