2012-02-23 25 views
9

MyClassIDParentIDList<MyClass>作爲Children(ID/PARENTID)列表,以分級列表

我有這樣

ID ParentID 
1 0 
2 7 
3 1 
4 5 
5 1 
6 2 
7 1 
8 6 
9 0 
10 9 

輸出(分層列表)的MyClass列表作爲List<MyClass>

1 __ 3 
|__ 5__ 4 
|__ 7__ 2__ 6__ 8 
    |__ 11 

9 __10 

在linq中實現這個最簡單的方法是什麼?
PS:ParentID沒有排序

編輯:
我嘗試:

class MyClass 
{ 
    public int ID; 
    public int ParentID; 
    public List<MyClass> Children = new List<MyClass>(); 
    public MyClass(int id, int parent_id) 
    { 
     ID = id; 
     ParentID = parent_id; 
    } 
} 

初始化樣本數據,以期達到分層數據

List<MyClass> items = new List<MyClass>() 
{ 
    new MyClass(1, 0), 
    new MyClass(2, 7), 
    new MyClass(3, 1), 
    new MyClass(4, 5), 
    new MyClass(5, 1), 
    new MyClass(6, 2), 
    new MyClass(7,1), 
    new MyClass(8, 6), 
    new MyClass(9, 0), 
    new MyClass(10, 9), 
    new MyClass(11, 7), 
}; 

Dictionary<int, MyClass> dic = items.ToDictionary(ee => ee.ID); 

foreach (var c in items) 
    if (dic.ContainsKey(c.ParentID)) 
     dic[c.ParentID].Children.Add(c); 

,你可以看到,很多的我不想要的東西仍然在字典中

+0

應的輸出是什麼類型的數據結構? – Jon 2012-02-23 08:00:13

+0

@Jon:請參閱我更新的問題 – 2012-02-23 08:03:42

+0

但是'List'不是一個分層數據結構。換句話說,你如何打算將一個'List'變成圖片樹? – Jon 2012-02-23 08:17:50

回答

13

對於分層數據,您需要遞歸 - foreach循環是不夠的。

Action<MyClass> SetChildren = null; 
SetChildren = parent => 
    { 
     parent.Children = items 
      .Where(childItem => childItem.ParentID == parent.ID) 
      .ToList(); 

     //Recursively call the SetChildren method for each child. 
     parent.Children 
      .ForEach(SetChildren); 
    }; 

//Initialize the hierarchical list to root level items 
List<MyClass> hierarchicalItems = items 
    .Where(rootItem => rootItem.ParentID == 0) 
    .ToList(); 

//Call the SetChildren method to set the children on each root level item. 
hierarchicalItems.ForEach(SetChildren); 

items是您使用的相同列表。注意如何在其內部調用SetChildren方法。這是構建層次結構的原因。

+1

這比OP的原始代碼性能低。字典方法遠遠優越。 – 2014-09-28 13:27:49

+0

不錯的用戶347805,它爲我工作 – Shailesh 2016-05-31 11:40:16

+0

這是很好的技巧..!它也適用於我.. – 2017-02-12 03:42:15

32

如果在過濾之前構建父子關係,遞歸在這裏不是必需的。由於列表中的成員保持相同的對象,只要您將列表中的每個成員與其直接孩子關聯起來,就會建立所有必要的關係。

這可以在兩條線進行:

items.ForEach(item => item.Children = items.Where(child => child.ParentID == item.ID) 
              .ToList()); 
List<MyClass> topItems = items.Where(item => item.ParentID == 0).ToList(); 
+0

我沒有想到這一點。你是對的。創建層次結構不需要遞歸,只有**遍歷**。 – user347805 2013-04-04 22:05:07

+0

遍歷不太。 :) – DiVan 2013-06-04 05:48:33

+0

剛剛用於類似的項目。美麗的解決方案和高效。 – 2014-12-10 13:37:11

1

我也需要這樣的功能,並在我的數據庫卡或記錄比較兩種方法,並找到方法第2比1 :)快,現在是有限的,但第一種方法需要花費4倍的時間才能完成。

可能是這可以幫助那些有時間意識的人。

1方法


public JsonResult CardData() 
    { 
     var watch = System.Diagnostics.Stopwatch.StartNew(); 
     OrgChartWithApiContext db = new OrgChartWithApiContext(); 

     var items = db.Cards.ToList(); 
     Action<Card> SetChildren = null; 
     SetChildren = parent => { 
      parent.Children = items 
       .Where(childItem => childItem.ParentId == parent.id) 
       .ToList(); 

      //Recursively call the SetChildren method for each child. 
      parent.Children 
       .ForEach(SetChildren); 
     }; 

     //Initialize the hierarchical list to root level items 
     List<Card> hierarchicalItems = items 
      .Where(rootItem => !rootItem.ParentId.HasValue) 
      .ToList(); 

     //Call the SetChildren method to set the children on each root level item. 
     hierarchicalItems.ForEach(SetChildren); 
     watch.Stop(); 
     var timetaken = watch.ElapsedMilliseconds; 

     return new JsonResult() { Data = hierarchicalItems, ContentType = "Json", JsonRequestBehavior = JsonRequestBehavior.AllowGet }; 
    } 

方法2


public JsonResult Card2Data() 
    { 
     var watch = System.Diagnostics.Stopwatch.StartNew(); 
     OrgChartWithApiContext db = new OrgChartWithApiContext(); 
     var items = db.Cards.ToList(); 
     List<Card> topItems = items.Where(item => !item.ParentId.HasValue).ToList(); 
     topItems.ForEach(item => item.Children = items.Where(child => child.ParentId == item.id).ToList()); 
     watch.Stop(); 
     var timetaken = watch.ElapsedMilliseconds; 
     return new JsonResult() { Data = topItems, ContentType = "Json", JsonRequestBehavior = JsonRequestBehavior.AllowGet }; 
    }