Search code examples
linqentity-frameworkselecthierarchy

Rendering a hierarchy using LINQ?


Let say we have a class

Category
{
   ID,
   Name,
   ParentID
}

and a List

1, 'Item 1', 0
2, 'Item 2', 0
3, 'Item 3', 0
4, 'Item 1.1', 1
5, 'Item 3.1', 3
6, 'Item 1.1.1', 4
7, 'Item 2.1', 2

Can we using LINQ to render a tree like:

Item 1
 Item 1.1
  Item 1.1.1
Item 2
 Item 2.1
Item 3
 Item 3.1

Any help is appreciated!


Solution

  • Here's the "LINQ-only" version:

    Func<int, int, string[]> build = null;
    build = (p, n) =>
    {
        return (from x in categories
                where x.ParentID == p
                from y in new[]
                {
                    "".PadLeft(n)+ x.Name
                }.Union(build(x.ID, n + 1))
                select y).ToArray();
    };
    var lines = build(0, 0);
    

    Yes, it's recursive LINQ.


    Per NVA's request, here's the way to make all "orphan" records become root records:

    Func<IEnumerable<int>, int, string[]> build = null;
    build = (ps, n) =>
    {
        return (from x in categories
                where ps.Contains(x.ParentID)
                from y in new[]
        {
            "".PadLeft(n)+ x.Name
        }.Union(build(new [] { x.ID }, n + 1))
                select y).ToArray();
    };
    
    var roots = (from c in categories
                 join p in categories on c.ParentID equals p.ID into gps
                 where !gps.Any()
                 orderby c.ParentID
                 select c.ParentID).Distinct();
    
    var lines = build(roots, 0);