English 中文(简体)
将具有父/子层次结构的通用列表<T>读取到保留父/子层级结构的数据表中
原标题: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  

…变成一个单位列表,也就是列表,每个单位都可以有另一个层次不受限制的列表。现在,我想将List转换为具有父/子层次结构的表格格式。

数据表应该是这样的:

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 find.

问题回答

递归是正确的方法,但我将建议使用LINQ方法,尤其是当这个问题被标记为LINQ时。

LINQ的一个好处是,扩展方法可以消除很多复杂性,留下简单的查询来简单地表达业务逻辑。

下面是我用来压平递归结构的方法:

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);
}

请注意对Flatten的递归调用,这是在函数上定义的扩展方法,该函数从给定的父项返回子项。

现在我们可以定义Func<;T、 IEnumerable<;T>>如下所示:

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

然后,假设所有DimensionParentChildren属性都不为null,我们可以使用此查询生成要添加到表中的记录列表:

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

现在,如果有任何属性为<code>null</code>,则修复方法如下。

f重新定义为:

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

并添加此扩展方法:

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

现在查询的工作方式如下:

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,
    };

仍然非常相似,但null安全。

我希望这能有所帮助。

一个简单的递归算法会做得很好。。。

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); 
  }
}

为您拥有的每个维度对象调用AddSubTree





相关问题
Anyone feel like passing it forward?

I m the only developer in my company, and am getting along well as an autodidact, but I know I m missing out on the education one gets from working with and having code reviewed by more senior devs. ...

NSArray s, Primitive types and Boxing Oh My!

I m pretty new to the Objective-C world and I have a long history with .net/C# so naturally I m inclined to use my C# wits. Now here s the question: I feel really inclined to create some type of ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

How to Use Ghostscript DLL to convert PDF to PDF/A

How to user GhostScript DLL to convert PDF to PDF/A. I know I kind of have to call the exported function of gsdll32.dll whose name is gsapi_init_with_args, but how do i pass the right arguments? BTW, ...

Linqy no matchy

Maybe it s something I m doing wrong. I m just learning Linq because I m bored. And so far so good. I made a little program and it basically just outputs all matches (foreach) into a label control. ...