2012-02-23 2 views
9

MyClass состоит из IDParentID и List<MyClass>, как Children(ID ParentID /) список для иерархического списка

У меня есть список MyClass как этот

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

Output (иерархический список) в качестве List<MyClass>

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

9 __10 

Каков самый простой способ достичь этого в linq?
PS: ParentID не сортируется

Edit:
Моя попытка:

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

+0

@Jon: Пожалуйста, обратитесь к моему обновленному вопросу –

+0

Но «Список» не является иерархической структурой данных. Иными словами, как вы предлагаете превратить «Список» в изображенное дерево? – Jon

ответ

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. Метод словаря намного превосходит. –

+0

Nice user347805, Его работа для меня – Shailesh

+0

Это хороший трюк .. !! он работает для меня тоже .. !! –

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

+0

Перемещение не слишком. :) – DiVan

+0

Просто использовал это для аналогичного проекта. Красивое решение и эффективность тоже. –

1

Я требуется такая функциональность и сравнить оба метода и найти способ второй быстрее, чем 1 :), сейчас в моих картах базы данных или записей ограничены, но 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 }; 
    } 
Смежные вопросы