2012-02-23 15 views
9

MyClass consta de IDParentID y List<MyClass> como Children(ParentID ID /) lista a la lista jerárquica

tengo lista de MyClass como este

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

de salida (lista jerárquica) como List<MyClass>

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

9 __10 

¿Cuál es la forma más sencilla de lograr esto en linq?
PS: ParentID no ordenadas

Editar:
Mi intento:

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

inicializar datos de ejemplo y tratar de llegar a los datos jerárquicos

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

como se puede ver, un montón de artículos que aún no quiero en el diccionario

+0

¿Qué tipo de estructura de datos debe ser la salida en? – Jon

+0

@Jon: Por favor, consulte mi pregunta actualizada –

+0

Pero una 'Lista' no es una estructura de datos jerárquica. Para decirlo de otra manera, ¿cómo propones convertir una 'Lista' en el árbol ilustrado? – Jon

Respuesta

13

Para datos jerárquicos, necesita recursión; un bucle foreach no será suficiente.

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 es la misma lista que usted utiliza. Observe cómo se llama el método SetChildren dentro de sí mismo. Esto es lo que construye la jerarquía.

+1

Esto es menos eficiente que el código original de OPs. El método del diccionario es muy superior. –

+0

Nice user347805, Funciona para mí – Shailesh

+0

Este es un buen truco .. !! ¡Funciona para mí también ...! –

32

La recursividad no es necesaria aquí si crea las relaciones padre-hijo antes de filtrar. Como los miembros de la lista siguen siendo los mismos objetos, siempre que asocie a cada miembro de la lista con sus hijos inmediatos, se construirán todas las relaciones necesarias.

Esto se puede hacer de dos líneas:

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

No pensé en eso. Estás en lo correcto. La creación de la jerarquía no requiere recursividad, solo ** atravesar ** lo hace. – user347805

+0

Atravesar no lo hace también. :) – DiVan

+0

Acabo de usar esto para un proyecto similar. Hermosa solución y eficiente también. –

1

He necesarios, funcionalidad y comparar ambos métodos y encontrar segundo método es más rápido que el primero :), en este momento en mis tarjetas de bases de datos o registros son limitadas, pero Primer método que toma 4 veces más tiempo para completar.

puede ser esto puede ayudar a aquellos que son conscientes del tiempo.

1 método


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

método 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 }; 
    }