2016-03-22 100 views
0

我有什麼應該是一個相當無足輕重的問題,但我想確保我在.Net 4.5中以最「優雅」的方式做到這一點,我想一些比我更聰明的人的意見。通用樹結構 - 如何填充組織結構圖

我有一個類,它表示一個通用的樹結構,例如:

public class TreeNode<T> 
    { 
     List<TreeNode<T>> Children; 

     T Item {get;set;} 

     public TreeNode (T item) 
     { 
      Item = item; 
     } 

     public TreeNode<T> AddChild(T item) 
     { 
      TreeNode<T> nodeItem = new TreeNode<T>(item); 
      Children.Add(nodeItem); 
      return nodeItem; 
     } 
    } 

現在,我代表該組織的僱員一個Person類。每個Person對象都有一個指向其上級的IDBossID

多位員工可以擁有相同的老闆,因此我試圖用此樹結構創建組織結構圖。

頂部節點將是Person對象,其中BossID爲空(它是一個int?)。我可以快速獲得LINQ。

這是下一步令我困惑的一點。有多種方法,但對我來說似乎有點草率,我知道必須有一種更容易/更優雅的方式來填充組織結構圖的其餘部分。

所以現在我有一個通用對象List<Person>持有所有員工,其各種BossID和這個通用的樹結構,我可以添加子節點。

這都是非常基本的,但是填充樹的正確順序是什麼?我遞歸地應該迭代線?我知道這裏涉及回溯,這是我陷入困境的地方。

我很抱歉,我的背景不在計算機科學,如果是我意識到樹結構,鏈表和其他一切都是微不足道的東西。但這是我第一次嘗試,我想看看它是如何正確完成的。

我很欣賞任何指導。

+0

所以基本上你的問題是如何創建組織樹,因爲你有人的名單? –

+0

就這麼簡單。我有那個泛型樹類,我有一個List對象,它們有自己的ID和老闆的ID。我只想知道4.5下最乾淨的方法是什麼。我知道我可以查找如何填充一棵樹,但有一些非常差的例子,只是尋找輸入。我已經在這裏看到了一些驚人的魔力,特別是像LINQ這樣的事情,這些都極大地簡化了我的代碼。 – Patrick

回答

2

因此,考慮到你有定義爲這樣的Person類:

public class Person 
{ 
    public int ID; 
    public int? BossID; 
} 

...和你有一個List<Person>定義爲people那麼這個工程:

var lookup = people.ToLookup(p => p.BossID); 

Action<TreeNode<Person>> addChildren = null; 
addChildren = p => 
{ 
    foreach (var child in lookup[p.Item.ID]) 
    { 
     var childNode = p.AddChild(child); 
     addChildren(childNode); 
    } 
}; 

var trees = 
    from boss in lookup[null] 
    select new TreeNode<Person>(boss); 

foreach (var tree in trees) 
{ 
    addChildren(tree); 
} 

這是假設你可能有一個以上的老闆與null。如果你不那麼好,只需運行這個代碼並執行trees.First()

我用的TreeNode<T>的定義是這樣的:

public class TreeNode<T> 
{ 
    private List<TreeNode<T>> Children; 

    public T Item { get; set; } 

    public TreeNode(T item) 
    { 
     this.Item = item; 
     this.Children = new List<TreeNode<T>>(); 
    } 

    public TreeNode<T> AddChild(T item) 
    { 
     var nodeItem = new TreeNode<T>(item); 
     this.Children.Add(nodeItem); 
     return nodeItem; 
    } 
} 

你可以縮短TreeNode<T>這雖然:

public class TreeNode<T> : List<TreeNode<T>> 
{ 
    public T Item { get; set; } 

    public TreeNode(T item) 
    { 
     this.Item = item; 
    } 
} 

...那麼你需要修改addChildren這樣的:

Action<TreeNode<Person>> addChildren = null; 
addChildren = p => 
{ 
    foreach (var child in lookup[p.Item.ID]) 
    { 
     var childNode = new TreeNode<Person>(child); 
     p.Add(childNode); 
     addChildren(childNode); 
    } 
}; 

...但是你會擁有所有的標準rd List<>運營商可用於TreeNode<T>

+0

@Patrick - 如果你確定只有一個老闆,那麼做'var boss = trees.First();'。 – Enigmativity

+0

在這種情況下,只有一個老闆應該存在Single/SingleOrDefault會更好,因爲在此之後,您將知道是否存在數據錯誤,因爲只允許一個老闆 –

+0

@Enigmativity我正在使用您的代碼接受新方法一個參數,所有的人('List people')。 'people.Count'等於25開頭。它沒有按預期工作。 'foreach(樹中的var樹)'這一行進入循環一次,調用'addChildren(tree);'where'tree.Count = 0'。我不確定問題是什麼。 – Patrick