Sage Sage - 4 years ago 106
C# Question

Find Nesting Level In List<> Using Properties

I'm trying to build a tree structure with some data that I'm receiving from a service. Unfortunately, I have no control over the structure of the data that I'm receiving. The object is built as such:

class Module
{
public string ModuleCode {get;set;}
public string ParentCode {get;set;}
}


Basically, I am getting a list of around 200 of these objects and I need to find a way to sort through them and arrange them so that the children are correctly associated with their parents.

I have a working method now which is using foreach loops but it's ugly and is limited to the number of foreach loops that I hard code. I want something that is more dynamic.

foreach (var module in moduleList.Where(x => string.IsNullOrWhiteSpace(x.ParentCode)))
{
//Module Level 1 -- Only uppermost parent modules here
moduleLevel = 1;
_highestModuleLevel = _highestModuleLevel < moduleLevel ? moduleLevel : _highestModuleLevel;

foreach (var module2 in moduleList.Where(x => x.ParentCode == module.ModuleCode))
{
//Module Level 2 -- 1st children modules
moduleLevel = 2;
_highestModuleLevel = _highestModuleLevel < moduleLevel ? moduleLevel : _highestModuleLevel;

foreach (var module2 in moduleList.Where(x => x.ParentCode == module1.ModuleCode))
{
//Module Level -- children of the 2nd level modules
moduleLevel = 3;
_highestModuleLevel = _highestModuleLevel < moduleLevel ? moduleLevel : _highestModuleLevel;
//Goes on for however many foreaches I can nest
}
}
}


}

Like I said, this solution does work, but I really feel there has got to be a more programmatic, cleaner and more efficient way to handle this

Answer Source

Start With

The following assumes you have a method that gives you back a flattened list of Modules. Also, this is untested - might be typos or bugs... just approximately where I'd start to get you a hierarchical list of Modules. Notice that I added Parent and Children to your Module class.

class Module 
{
    public Module() 
    {
        this.Children = new List<Module>();
    }

    public string ModuleCode {get; set;}
    public string ParentCode {get; set;}
    public Module Parent {get; set;}
    public List<Module> Children {get; private set;}
}

static void main()
{
    List<Module> moduleList = GetFlattenedModules();
    IDictionary<string, Module> moduleCodeToModule = 
        moduleList.ToDictionary(m => m.ModuleCode);

    foreach (Module module in moduleList)
    {
        if (module.ParentCode != null) 
        {
            module.Parent = moduleCodeToModule[module.ParentCode];
            module.Parent.Children.Add(module);
        }
    }
}

What you get

What this gets you is your original list, but with each Module potentially having children, and potentially having a parent.

What you probably want

What you probably really want is a list of top level Modules only, and you databind against that thing. This is simple to get, with something like:

List<Module> topLevelModules = moduleList.Where(m => m.Parent == null).ToList();
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download