2009-12-21 24 views
14

Cómo convertir el objeto jerárquico anidado para aplanar objetos utilizando LINQ? Sé que podemos usar forec fácilmente para lograr eso. Pero me pregunto si hay alguna forma de escribirlo en LINQ.LINQ: cómo convertir el objeto jerárquico anidado para aplanar el objeto

class Person{ 
    public int ID {get;set} 
    public string Name {get;set} 
    public List<Person> Children {get;} 
} 

datos:

ID : 1 

Name : Jack 

Children 

2 | Rose 

3 | Paul 

me gusta convertir estos datos en formato de aplanar, como a continuación.

1 | Jack 

2 | Rose 

3 | Paul 

¿Cómo lo podemos hacer con Linq?

Respuesta

17

Si lo desea para aplanar un árbol de profundidad arbitraria de las personas, que sugieren lo siguiente:

public IEnumerable<Person> GetFamily(Person parent) 
{ 
    yield return parent; 
    foreach (Person child in parent.Children) // check null if you must 
     foreach (Person relative in GetFamily(child)) 
      yield return relative; 
} 

no hay realmente ninguna buena manera de acortar esto con LINQ, porque lambdas anónimos no pueden llamar a sí mismos de forma recursiva sin implementar Y. Usted podría "reducir" el método anterior para

return parent.Children.SelectMany(p => GetFamily(p)) 
         .Concat(new Person[] { parent }); 

o alternativamente

yield return parent; 
    foreach (Person relative in parent.Children.SelectMany(GetFamily)) 
     yield return relative; 

pero eso parece algo innecesario para mí.

+0

Por supuesto, los lambdas pueden llamarse a sí mismos. Aquí está Fibonacci usando una lambda recursiva: 'Func fib = null; fib = i => i <= 1? i: fib (i-1) + fib (i-2); ' –

+1

Dije" * anonymous * lambdas no pueden llamarse a sí mismos ", por lo que no puede escribir una sola expresión que devuelva el valor que desea - - Necesita declarar una función con nombre para recurse con. – mquander

+0

Entonces, al poner algo anónimo en una variable ¿ya no es anónimo? P.ej. 'var a = new {X = 5};'? Todavía llamaría a lo que 'a' hace referencia a un tipo anónimo. Microsoft dice incondicionalmente que ["Una expresión lambda es una función anónima"] (http://msdn.microsoft.com/en-us/library/bb397687.aspx) y mira el segundo ejemplo de [Métodos anónimos] (http: //msdn.microsoft.com/en-us/library/0yw3tz5k.aspx). Casi todo lo anónimo debe colocarse en algún tipo de variable o parámetro con nombre; de lo contrario, no son utilizables por el código. Eso no quiere decir que no sean anónimos. –

9

Este es un bonito, genérico y reutilizable método de extensión:

static public IEnumerable<T> Descendants<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> descendBy) 
{ 
    if (!source.IsNullOrEmpty()) 
    { 
     foreach (T value in source) 
     { 
      yield return value; 

      if (!descendBy(value).IsNullOrEmpty()) 
      { 
       foreach (T child in descendBy(value).Descendants<T>(descendBy)) 
       { 
        yield return child; 
       } 
      } 
     } 
    } 
} 

En el caso anterior, utilice la siguiente manera:

var allChildren = parent.Children.Descendants(p => p.Children); 

Una nit menor es que no incluye el original padre en la lista, tendrá que hacer eso.

Cuestiones relacionadas