2011-05-30 53 views
0

我已經改變了這個XML樹與單位名稱: 昏暗=尺寸閱讀泛型列表<T>與父/子層次結構成一個DataTable維護父/子層次

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


Dim2    
|---MG220  
    |---MG2222 

...進入單位名單又名列出每個單位可以有另一個名單與無限層次。現在我想將列表轉換爲具有父/子層次結構的表格格式。

這樣,應該在數據表的樣子:

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

} 

問:你會如何遍歷目錄和所有數據都寫入到一個DataTable? 必須有一個棘手的algaoryth我找不到。

回答

0

一個簡單的遞歸算法會做得很好......

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每一個維對象必須

+0

不起作用。傳遞給AddSubTree的單元通常是空拋出異常。其實一個維度不應該是空的......我想這不能在沒有把所有源代碼放在這裏的情況下解決......對不起Variant,但thx尋求幫助。我必須現在玩... – msfanboy 2011-05-31 10:08:46

1

遞歸是正確的做法在這裏,但我要提出一個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; 

然後,假設所有DimensionParent,並且Children屬性不爲空,我們可以用這個查詢產生的記錄列表添加表:

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

現在,如果任何屬性都null,這裏的修復。

重新定義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安全。

我希望這會有所幫助。

+0

謝謝。我給了你一點我可以再用一天的好片段。不是一個解決方案,因爲我意識到現有的代碼結構不同於我認爲/期望的,因此需要另一個解決方案,這非常簡單:) – msfanboy 2011-06-03 16:36:49