HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Building tree structure based on flat objects

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
objectsbuildingflatstructurebasedtree

Problem

You can find here a Follow-up question

Description

A List is returned by a 3rd party webservice, which will then be transformed to a List. These ArchiveDefinition objects are connected by Parent'.ArchiveNodeId == 'Child'.ParentId.

The root objects TypeOfArchive property will always have the value ArchiveType.Archive.

The goal of the given class below is to build a List of these flat object list to fill a treeview control.

The class in question

```
public class ArchiveBuilder
{
public static List Build(List entries)
{
List rootArchiveTreeEntries = new List();

if (entries != null && entries.Count > 0)
{
List rootEntries = GetRootEntries(entries);

foreach (ArchiveDefinition definition in rootEntries)
{
rootArchiveTreeEntries.Add(new ArchiveTreeEntry(definition));
entries.Remove(definition);
}

foreach (ArchiveTreeEntry parent in rootArchiveTreeEntries)
{
FillChildren(parent, entries);
}
}
return rootArchiveTreeEntries;
}

private static void FillChildren(ArchiveTreeEntry parent,
List entries)
{
if (entries.Count > 0)
{
List children = GetChildren(entries, parent.Id);

if (children.Count > 0)
{
RemoveChildren(entries, parent.Id);

foreach (ArchiveDefinition child in children)
{
ArchiveTreeEntry treeEntryChild = new ArchiveTreeEntry(child);
parent.AddChild(treeEntryChild);
FillChildren(treeEntryChild, entries);
}
}
}
}

private static List GetRootEntries(List entries)
{
return entries.FindAll(e => e.TypeOfArchive == ArchiveType.Archive);
}

private static List GetChildren(List entries, string parentID)

Solution

-
You could use the AddRange combined with the Except method inside of Build:

public static List Build(List entries)
{
    List rootArchiveTreeEntries = new List();

    if (entries != null && entries.Count > 0)
    {
        List rootEntries = GetRootEntries(entries);

        entries = rootArchiveTreeEntried.AddRange(rootEntries.Select(definition=> new ArchiveTreeEntry(definition)).Except(entries);

        foreach (ArchiveTreeEntry parent in rootArchiveTreeEntries)
        {
            FillChildren(parent, entries);
        }
    }
    return rootArchiveTreeEntries;
}


-
You have made the public method static, which in this case is probably fine but it does make it harder to unit test dependencies. I envisage the class being consumed, like this:

in app

var builder = new ArchiveBuilder();  
builder.Build(entities);


-
That said, the private methods are fine as static methods because the are an implementation detail.

  • The private methods can return/accept IEnumerable<> instead of List<>



-
From there, you could then re-write the method above to be:

public static List Build(List entries)
{
    List rootArchiveTreeEntries = new List();

    if (entries != null && entries.Count > 0)
    {
        entries = rootArchiveTreeEntried.AddRange(GetRootEntries(entries).Select(entry => new ArchiveTreeEntry(definition)).Except(entries);

        foreach (ArchiveTreeEntry parent in rootArchiveTreeEntries)
        {
            FillChildren(parent, entries);
        }
    }
    return rootArchiveTreeEntries;
}


So here is the completely re-written class:

public class ArchiveBuilder
{
    public IEnumerable Build(IEnumerable entries)
    {
        IEnumerable rootArchiveTreeEntries = new List();

        if (entries != null && entries.Count > 0)
        {
            entries = rootArchiveTreeEntried.AddRange(GetRootEntries(entries).Select(entry => new ArchiveTreeEntry(definition)).Except(entries);

            foreach (ArchiveTreeEntry parent in rootArchiveTreeEntries)
            {
                FillChildren(parent, entries);
            }
        }
        return rootArchiveTreeEntries;
    }

    private static void FillChildren(ArchiveTreeEntry parent,
                                 IEnumerable entries)
    {
        if (entries.Count > 0)
        {
            IEnumerable children = GetChildren(entries, parent.Id);

            if (children.Count > 0)
            {
                RemoveChildren(entries, parent.Id);

                foreach (ArchiveDefinition child in children)
                {
                    ArchiveTreeEntry treeEntryChild = new ArchiveTreeEntry(child);
                    parent.AddChild(treeEntryChild);
                    FillChildren(treeEntryChild, entries);
                }
            }
        }
    }

    private static IEnumerable GetRootEntries(IEnumerable entries)
    {
        return entries.FindAll(e => e.TypeOfArchive == ArchiveType.Archive);
    }

    private static IEnumerable GetChildren(IEnumerable entries, string parentID)
    {
        return entries.FindAll(e => e.ParentId == parentID);
    }

    private static void RemoveChildren(IEnumerable entries, string parentID)
    {
        entries.RemoveAll(e => e.ParentId == parentID);
    }
}


NB: I haven't compiled the class or tested it, so it might not work out the box.

Code Snippets

public static List<ArchiveTreeEntry> Build(List<ArchiveDefinition> entries)
{
    List<ArchiveTreeEntry> rootArchiveTreeEntries = new List<ArchiveTreeEntry>();

    if (entries != null && entries.Count > 0)
    {
        List<ArchiveDefinition> rootEntries = GetRootEntries(entries);

        entries = rootArchiveTreeEntried.AddRange(rootEntries.Select(definition=> new ArchiveTreeEntry(definition)).Except(entries);

        foreach (ArchiveTreeEntry parent in rootArchiveTreeEntries)
        {
            FillChildren(parent, entries);
        }
    }
    return rootArchiveTreeEntries;
}
var builder = new ArchiveBuilder();  
builder.Build(entities);
public static List<ArchiveTreeEntry> Build(List<ArchiveDefinition> entries)
{
    List<ArchiveTreeEntry> rootArchiveTreeEntries = new List<ArchiveTreeEntry>();

    if (entries != null && entries.Count > 0)
    {
        entries = rootArchiveTreeEntried.AddRange(GetRootEntries(entries).Select(entry => new ArchiveTreeEntry(definition)).Except(entries);

        foreach (ArchiveTreeEntry parent in rootArchiveTreeEntries)
        {
            FillChildren(parent, entries);
        }
    }
    return rootArchiveTreeEntries;
}
public class ArchiveBuilder
{
    public IEnumerable<ArchiveTreeEntry> Build(IEnumerable<ArchiveDefinition> entries)
    {
        IEnumerable<ArchiveTreeEntry> rootArchiveTreeEntries = new List<ArchiveTreeEntry>();

        if (entries != null && entries.Count > 0)
        {
            entries = rootArchiveTreeEntried.AddRange(GetRootEntries(entries).Select(entry => new ArchiveTreeEntry(definition)).Except(entries);

            foreach (ArchiveTreeEntry parent in rootArchiveTreeEntries)
            {
                FillChildren(parent, entries);
            }
        }
        return rootArchiveTreeEntries;
    }

    private static void FillChildren(ArchiveTreeEntry parent,
                                 IEnumerable<ArchiveDefinition> entries)
    {
        if (entries.Count > 0)
        {
            IEnumerable<ArchiveDefinition> children = GetChildren(entries, parent.Id);

            if (children.Count > 0)
            {
                RemoveChildren(entries, parent.Id);

                foreach (ArchiveDefinition child in children)
                {
                    ArchiveTreeEntry treeEntryChild = new ArchiveTreeEntry(child);
                    parent.AddChild(treeEntryChild);
                    FillChildren(treeEntryChild, entries);
                }
            }
        }
    }

    private static IEnumerable<ArchiveDefinition> GetRootEntries(IEnumerable<ArchiveDefinition> entries)
    {
        return entries.FindAll(e => e.TypeOfArchive == ArchiveType.Archive);
    }

    private static IEnumerable<ArchiveDefinition> GetChildren(IEnumerable<ArchiveDefinition> entries, string parentID)
    {
        return entries.FindAll(e => e.ParentId == parentID);
    }

    private static void RemoveChildren(IEnumerable<ArchiveDefinition> entries, string parentID)
    {
        entries.RemoveAll(e => e.ParentId == parentID);
    }
}

Context

StackExchange Code Review Q#58727, answer score: 2

Revisions (0)

No revisions yet.