I've got a List(Of HashSet(Of String))
. Is there a clear, one-line LINQ way to get a single HashSet(Of String)
containing all the strings in the list entry values?
For example, from the 3 hashsets {"A"}, {"A","B","C"}, and {"B","C","D"} I'd like a single hashset {"A","B","C","D"}.
I'm pretty sure I can do something with .Aggregate()
or .Accumulate()
.
C# or VB.NET explanations are equally helpful.
You can just use SelectMany
. In C#:
var newHashSet = new HashSet<string>(myListOfHashSets.SelectMany(x => x));
And in VB.NET:
Dim newHashSet As New HashSet(Of String)(myListOfHashSets.SelectMany(Function (x) x))
SelectMany
does exactly this. At a high level (omitting the generics and simplifying a bit), SelectMany
is implemented like:
static IEnumerable SelectMany(this source, Func selector)
{
IEnumerable results;
foreach (var item in source)
{
foreach (var result in selector(item))
{
results.add(result);
}
}
return results;
}
The above code is not actually accurate; instead it uses a yield return to perform the select lazily and uses no intermediate collection results
. Finally, the full signature is actually public static IEnumerable<TResult> SelectMany<TSource, TResult>(
this IEnumerable<TSource> source,
Func<TSource, IEnumerable<TResult>> selector)
, but the only important piece to understand is that selector returns a collection. If you have a collection of collections then using the identity function x => x
does exactly that.
So, it flattens collections of collections into a single collection. Using the identity function x => x
as the selector means that the elements of the inner collections are unchanged. So, as a few others have posted, the final answer would be:
var newSet = new HashSet(setOfSets.SelectMany(element => element));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With