2010-12-14 49 views
5

Je suis en train d'écrire une largeur profondeur première fonction traversal d'arbre, et ce que je veux faire est la suivante:Python idiomatique: Propagation des rendements ou des séquences d'aplatissement?

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

L'idée est de se retrouver avec une séquence (plat) de noeuds dans l'arbre .

Approche # 1: (se propageant à des rendements)

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

Approche # 2: (séquences aplanissement)

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

La première approche semble plus propre, mais je me sens bizarre explicitement yield ing chaque noeud dans le sous-arbre à chaque niveau.

La deuxième approche est laconique et un peu sale, mais elle correspond à ce que j'écrire dans Haskell:

traverse node = node : concatMap traverse (children node) 

Donc, ma question est: Quel est le meilleur? Ou est-ce que je manque une meilleure 3ème option?

+0

Liste compréhensions ferait ce nettoyeur. –

+0

Rafe: Ecrivez une réponse et montrez-moi! :-) – perimosocordiae

+1

Je voudrais voir une liste de compréhension pour cela ... vous auriez besoin de l'aplatir à la fin, non? En ce qui me concerne, la solution «en chaîne» est merveilleuse. – delnan

Répondre

4

[UPDATE] Voir PEP-380, ce rendement toute la syntaxe est disponible à partir Python 3.3 comme yield from:

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

@ THC4k, c'est une bonne question :-) Je c & p le code d'un autre script, je suppose que j'essayais quelque chose en ce moment. Mis à jour, il devrait fonctionner sans utiliser "list".[oups, vous avez supprimé votre commentaire?] – tokland

+0

ouais quand vous l'avez changé;) –

+0

@ THC4k, ouais, désolé, je ne suis jamais satisfait de mes réponses et je continue à les éditer ;-) – tokland

3

Je vais en premier lieu. Vous aurez fini de multiplier les rendements après quelques occasions. :-)

1

Ceci est une question d'opinion, donc toutes les réponses seront juste des jugements de valeur. Pour autant que je puisse penser il n'y a pas de troisième voie élégante, cependant. Mon opinion est que la première voie gagne haut la main. C'est plus clair et plus facile à lire - Python n'est pas Haskell, même s'il peut faire des choses fonctionnelles, et souvent l'approche fonctionnelle n'est pas aussi nette.

0

avec position Traversant noeud:

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)