2012-02-23 12 views
9

MyClass è costituito da IDParentID e List<MyClass> come Children(ID/ParentID) lista di Elenco gerarchico

ho lista di MyClass come questo

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

uscita (Elenco gerarchico) come List<MyClass>

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

9 __10 

Qual è il modo più semplice per ottenere questo in linq?
PS: ParentID non allineati

Edit:
mia prova:

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

inizializzare i dati di esempio e cercare di raggiungere i dati gerarchici

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

, come si può vedere, un sacco di articoli che non voglio ancora nel dizionario

+0

Che tipo di struttura dati dovrebbe essere l'uscita in? – Jon

+0

@Jon: Si prega di fare riferimento alla mia domanda aggiornata –

+0

Ma un 'Elenco' non è una struttura gerarchica dei dati. Per dirla diversamente, come proponi di trasformare un 'Elenco' nell'albero nella foto? – Jon

risposta

13

Per i dati gerarchici, è necessaria la ricorsione: un ciclo foreach non è sufficiente.

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 è lo stesso elenco che si utilizza. Si noti come il metodo SetChildren viene chiamato all'interno di se stesso. Questo è ciò che costruisce la gerarchia.

+1

Questo è meno performante del codice originale OPs. Il metodo del dizionario è di gran lunga superiore. –

+0

Nice user347805, funziona per me – Shailesh

+0

Questo è un bel trucco .. !! funziona anche per me .. !! –

32

La ricorsione non è necessaria qui se si creano le relazioni padre-figlio prima del filtro. Poiché i membri della lista rimangono gli stessi oggetti, purché associ ciascun membro della lista ai suoi figli immediati, verranno create tutte le relazioni necessarie.

questo può essere fatto in due linee:

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

Non ci ho pensato. Hai ragione La creazione della gerarchia non richiede la ricorsione, solo ** lo attraversa **. – user347805

+0

Anche attraversare non lo fa. :) – DiVan

+0

Utilizzato solo per un progetto simile. Bella soluzione ed efficiente anche. –

1

ho richiesto tale funzionalità e confrontare entrambi i metodi e trovare il metodo secondo è più veloce di prima :), in questo momento le mie carte di database o record sono limitati, ma 1o metodo richiede 4 volte più tempo per completare.

può essere questo può aiutare per coloro che sono consapevoli del tempo.

1 metodo


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

metodo 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 }; 
    } 
Problemi correlati