6

I have a question for you linq experts out there! In a nested list of Component instances, I need to know if there is a component of a particular type in it. Can it be expressed by linq? Take into account that there may be application.Components[0].Components[0].Components[0]... My question is oriented to recursive queries in linq!

I leave you the entities for you to have some idea of the model.

public class Application
{
    public List<Component> Components { get; set; }
}

public class Component
{
    public ComponentType Type { get; set; }
    public List<Component> Components { get; set; }
}

public enum ComponentType
{
    WindowsService,
    WebApplication,
    WebService,
    ComponentGroup
}

2 Answers 2

5

You want to know if any of the components in a component is of a given type?

var webType = ComponentType.WebApplication;
IEnumerable<Component> webApps = from c in components
                                 from innerComp in c.Components
                                 where innerComp.Type == webType;
bool anyWebApp = webApps.Any();

what about innercomp.components?

Edit: So you want to find components of a given type recursively not only on the top or second level. Then you can use following Traverse extension method:

public static IEnumerable<T> Traverse<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> fnRecurse)
{
    foreach (T item in source)
    {
        yield return item;

        IEnumerable<T> seqRecurse = fnRecurse(item);
        if (seqRecurse != null)
        {
            foreach (T itemRecurse in Traverse(seqRecurse, fnRecurse))
            {
                yield return itemRecurse;
            }
        }
    }
}

to be used in this way:

var webType = ComponentType.WebApplication;
IEnumerable<Component> webApps = components.Traverse(c => c.Components)
                                 .Where(c => c.Type == webType);
bool anyWebApp = webApps.Any();

sample data:

var components = new List<Component>() { 
    new Component(){ Type=ComponentType.WebService,Components=null },
    new Component(){ Type=ComponentType.WebService,Components=new List<Component>(){
        new Component(){ Type=ComponentType.WebService,Components=null },
        new Component(){ Type=ComponentType.ComponentGroup,Components=null },
        new Component(){ Type=ComponentType.WindowsService,Components=null },
    } },
    new Component(){ Type=ComponentType.WebService,Components=null },
    new Component(){ Type=ComponentType.WebService,Components=new List<Component>(){
        new Component(){ Type=ComponentType.WebService,Components=new List<Component>(){
            new Component(){Type=ComponentType.WebApplication,Components=null}
        } },
        new Component(){ Type=ComponentType.WindowsService,Components=null },
        new Component(){ Type=ComponentType.WebService,Components=null },
    } },
    new Component(){ Type=ComponentType.WebService,Components=null },
    new Component(){ Type=ComponentType.ComponentGroup,Components=null },
    new Component(){ Type=ComponentType.WebService,Components=null },
};
Sign up to request clarification or add additional context in comments.

3 Comments

what about innercomp.components?
I am eating rainbows... Let me check
You are the ultimate linq, extension method, recursion master Tim!
1
if( Components.Any( c => c.Type == ComponentType.WindowsService ) )
{
   // do something
}

or you can do

var listContainsAtLeastOneService = 
    ( from c in Components
      where c.Type == ComponentType.WindowsService
      select c ).Any( );

Comments

Your Answer

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.