1
\$\begingroup\$

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?

asked Jun 29, 2021 at 10:16
\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

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();
  1. With SelectMany we are reducing the dimensions (flattening) from IEnumerable<IEnumerable<string>> to IEnumerable<string>
  2. With Select we retrieve the string value from its wrapper class
  3. With Distinct we are making sure that we are getting rid of from all duplicates
  4. With ToHashSet we simply convert the IEnumerable<string> to ISet<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,
answered Jun 29, 2021 at 10:31
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.