2010-12-14 40 views
5

Piszę Szerokość głębokości pierwszego drzewa funkcji przejścia, a to, co chcę zrobić to w ten sposób:Python Idiomatic: Propagowanie plonów lub sekwencji spłaszczania?

def traverse(node): 
    yield node 
    for n in node.children: 
     yield_all traverse(n) # << if Python had a yield_all statement 

Chodzi o to, aby skończyć z (płaski) sekwencji węzłów w drzewie .

Podejście nr 1: (plony propagujące)

def traverse(node): 
    yield node 
    for n in node.children: 
     for m in traverse(n): 
      yield m 

Podejście nr 2: (sekwencje spłaszczania)

def traverse(node): 
    return itertools.chain([node],*(traverse(n) for n in node.children)) 

Pierwsze podejście wydaje się bardziej czyste, ale czuję się dziwnie wyraźnie yield ing każdego węzła w poddrzewie na każdym poziomie.

Drugie podejście jest lakoniczny i lekko brudne, ale to pasuje do tego, co chciałbym napisać w Haskell:

traverse node = node : concatMap traverse (children node) 

Więc moje pytanie brzmi: Który jest lepszy? Czy może brakuje mi najlepszej trzeciej opcji?

+0

Ułatwienia Lista uczyniłoby to czystsze. –

+0

Rafe: Napisz odpowiedź i pokaż mi! :-) – perimosocordiae

+1

Chciałbym zobaczyć listę zrozumiałą dla tego ... musiałbyś ją spłaszczyć w końcu, prawda? O ile mi wiadomo, rozwiązanie "łańcuchowe" jest wspaniałe. – delnan

Odpowiedz

4

[Update] Patrz PEP-380 to wydajność wszystkich składni już od Python 3.3 jak yield from:

def traverse(node): 
    yield node 
    for n in node.children: 
     yield from traverse(n) 
+0

@ THC4k, to jest dobre pytanie :-) C & p kodu z innego skryptu, myślę, że próbowałem coś w tej chwili. Zaktualizowany, powinien działać bez użycia "listy".[Oj, skasowałeś swój komentarz?] – tokland

+0

tak, kiedy to zmieniłeś;) –

+0

@ THC4k, tak, przepraszam, nigdy nie jestem usatysfakcjonowany moimi odpowiedziami i ciągle je edytuję ;-) – tokland

3

by przejść z pierwszego. Po kilkukrotnym rozrachunku będziesz się nadmiernie powiększał plony. :-)

1

To jest pytanie poglądowe, więc wszystkie odpowiedzi będą jedynie wartościującymi wyrokami. O ile mi wiadomo, nie ma eleganckiej trzeciej drogi.

Moim zdaniem pierwsza droga wygrywa. Jest czytelniejszy i łatwiejszy do odczytania - Python nie jest Haskellem, mimo że może sprawiać pewne funkcjonalne rzeczy, a często podejście funkcjonalne po prostu nie wygląda tak zgrabnie.

0

Ruch ze stanowiska węzła:

def iter_tree(t, i=0, j=0): 
    yield (i, j), t 
    for j, n in enumerate(t.children): 
     yield from iter_tree(n, i + 1, j) 

for (i, j), n in iter_tree(t): 
    print(i*' ', (i, j), n)