Problem
Code
List<Element> elements = GetElementsList();
ISet<string> usedInnerElements = new HashSet<string>();
foreach (Element element in elements)
{
foreach (InnerElement innerElement in element.InnerCollection.InnerElements)
{
usedInnerElements.Add(innerElement.SomeValue);
}
}
class Element
{
public InnerCollection InnerCollection { get; set; }
}
class InnerCollection
{
public List<InnerElement> InnerElements { get; set; }
}
class InnerElement
{
public string SomeValue { get; set; }
}
This code scan inner collections of some other collection and save only unique values.
Question
Is there any way to present it in more fluent way using LINQ method syntax?
Solution
If we can assume that none of the values can be null
then the simplest solution I can think of:
ISet<string> usedInnerElements = elements
.SelectMany(coll => coll.InnerCollection.InnerElements
.Select(elem => elem.SomeValue))
.Distinct()
.ToHashSet();
- With
SelectMany
we are reducing the dimensions (flattening) fromIEnumerable<IEnumerable<string>>
toIEnumerable<string>
- With
Select
we retrieve thestring
value from its wrapper class - With
Distinct
we are making sure that we are getting rid of from all duplicates - With
ToHashSet
we simply convert theIEnumerable<string>
toISet<string>
Test Input:
var elements = new List<Element>
{
new Element
{
InnerCollection = new InnerCollection
{
InnerElements = new List<InnerElement>
{
new InnerElement { SomeValue = "A" },
new InnerElement { SomeValue = "C" },
new InnerElement { SomeValue = "E" },
}
}
},
new Element
{
InnerCollection = new InnerCollection
{
InnerElements = new List<InnerElement>
{
new InnerElement { SomeValue = "E" },
new InnerElement { SomeValue = "A" },
new InnerElement { SomeValue = "B" },
}
}
}
};
...
Console.WriteLine(string.Join(",", usedInnerElements));
Test output:
A,C,E,B
If you have to deal with null values then the query might look like this:
ISet<string> usedInnerElements = elements
.Where(coll => coll != null
&& coll.InnerCollection != null
&& coll.InnerCollection.InnerElements != null)
.SelectMany(coll => coll.InnerCollection.InnerElements
.Where(elem => elem != null)
.Select(elem => elem.SomeValue))
.Distinct()
.ToHashSet();
Test input
var elements = new List<Element>
{
null,
new Element
{
InnerCollection = null
},
new Element
{
InnerCollection = new InnerCollection
{
InnerElements = null
}
},
new Element
{
InnerCollection = new InnerCollection
{
InnerElements = new List<InnerElement>
{
new InnerElement { SomeValue = "E" },
new InnerElement(),
null
}
}
}
};
Test output
E,