开发者

Read a generic List<T> with parent/child hierarchy into a datatable preserving the parent/child hierarchy

I have transformed this XML tree with the names of the units: Dim = Dimension

Dim1            
|---MG1     
    |---M1  
    |---M2  
    |---M3  
        |---MG31
        |---MG32


Dim2            
|---MG220       
    |---MG2222  

...into a List of Units aka List where every Unit can have another List with unlimited hierarchy. Now I want to transform the List to a tabular format with the parent/child hierarchy.

That way should the datatable look like:

Dimension...Parent..Child
Dim1........Dim1....MG1
Dim1........MG1.....M1
Dim1........MG1.....M2
Dim1........Dim1....MG2
Dim1........MG1.....M3
Dim1........M3......MG31
Dim1........M3......MG32
Dim2........Dim2....MG220
Dim2........MG220...MG2222

public class Unit           
{           
   public String Name { get; set; }         
   public Unit Dimension { get; set; }          
   public UnitParent { get; set; }          
   public List<Unit> Children { get; set; }         

}

Question: How would you iterate the List and write all the data into a DataTable ? There must be a tricky algoryth I can not 开发者_如何学JAVAfind.


Recursion is the right approach here, but I'm going to suggest a LINQ approach - especially as this question was tagged with LINQ.

One of the nice things with LINQ is that extension methods can take away a lot of complexity and leave simple queries that express the business logic simply.

So here's what I use to flatten recursive structures:

public static IEnumerable<T> Flatten<T>(this Func<T, IEnumerable<T>> @this, T root)
{
    var head = new [] { root, };
    var tail =
        from c in @this(root)
        where !c.Equals(root)
        from d in @this.Flatten(c)
        select d;
    return head.Concat(tail);
}

Note the recursive call to Flatten and that this is an extension method defined on the function that returns the children from a given parent item.

Now we can define the Func<T, IEnumerable<T>> like this:

Func<Unit, IEnumerable<Unit>> f = u => u.Children;

And then, assuming that all Dimension, Parent, and Children properties are not null, we can use this query to produce the list of records to add to the table:

var records =
    from r in dimensions
    from d in f.Flatten(r)
    select new
    {
        Dimension = d.Dimension.Name,
        Parent = d.Parent.Name,
        d.Name,
    };

Now, if any of the properties are null, here's the fix.

Redefine f as:

Func<Unit, IEnumerable<Unit>> f = u => u.Children ?? new List<Unit>();

And add this extension method:

public static R ValueOrNull<T, R>(this T @this, Func<T, R> selector)
    where R : class
{
    return @this != null ? selector(@this) : null;
}

Now the query works like this:

var records =
    from r in dimensions
    from d in f.Flatten(r)
    select new
    {
        Dimension = d.Dimension.ValueOrNull(x => x.Name),
        Parent = d.Parent.ValueOrNull(x => x.Name),
        d.Name,
    };

Still very similar, but null safe.

I hope this helps.


A simple recursive algorithm will do fine...

function AddSubTree(Unit unit) {
  if (unit != unit.Dimension)
    AddItemToDataTable(unit.Dimension.Name, unit.UnitParent.Name, unit.Name);
  foreach (Unit childUnit in unit.Children) {
    AddSubTree(childUnit); 
  }
}

you call AddSubTree for every dimension object you have

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜