2009-12-21 1 views
14

Jak skonwertować zagnieżdżony obiekt hierarchiczny w celu spłaszczenia obiektów przy użyciu LINQ? Wiem, że możemy łatwo użyć pętli foreach, aby to osiągnąć. Ale zastanawiam się, czy istnieje sposób, aby napisać to w LINQ.LINQ: Jak skonwertować zagnieżdżony obiekt hierarchiczny, aby spłaszczyć obiekt?

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

danych:

ID : 1 

Name : Jack 

Children 

2 | Rose 

3 | Paul 

Chciałbym przekształcić te dane w formacie spłaszczyć jak poniżej.

1 | Jack 

2 | Rose 

3 | Paul 

Jak możemy to zrobić z Linq?

Odpowiedz

17

Jeśli chcesz go spłaszczyć dowolnie głębokie drzewa ludzi, proponuję następujące:

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

Nie ma naprawdę dobry sposób, aby skrócić ten z LINQ, ponieważ anonimowych lambdas nie można nazwać sami rekurencyjnie bez wdrożenia Y. można by "zmniejszyć" powyższą metodę

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

lub alternatywnie

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

, ale wydaje mi się to niepotrzebne.

+0

Oczywiście lambdas może się nazywać. Oto Fibonacci używające rekurencyjnego lambda: 'Func fib = null; fib = i => i <= 1? i: fib (i-1) + fib (i-2); ' –

+1

Powiedziałem:" * anonimowy * lambdas nie może nazywać siebie ", dlatego nie może napisać pojedynczego wyrażenia, które zwraca wartość, którą chce - - musi zadeklarować nazwaną funkcję, z którą ma się powtarzać. – mquander

+0

Więc umieszczając coś anonimowego w zmiennej, nie jest już anonimowy? Na przykład. 'var a = new {X = 5};'? Nadal nazywam to, co "a" odnosi się do anonimowego typu. Microsoft bezwarunkowo mówi, że ["Wyrażenie lambda jest funkcją anonimową"] (http://msdn.microsoft.com/en-us/library/bb397687.aspx) i spójrz na drugi przykład [Anonymous Methods] (http: //msdn.microsoft.com/en-us/library/0yw3tz5k.aspx). Prawie wszystko, co anonimowe, należy umieścić w jakiejś nazwanej zmiennej lub parametrze; w przeciwnym razie nie można ich użyć za pomocą kodu. To nie znaczy, że nie są anonimowi. –

9

Jest to miłe, rodzajowe i wielokrotnego użytku metodę rozszerzenia:

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

W powyższym przypadku należy użyć tak:

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

Jedno drobne nit jest to, że nie zawiera oryginał rodzic na liście, musisz to zrobić.