2010-12-14 2 views
5

Я пишу ширину глубину первого дерева функцию обхода, и то, что я хочу сделать это:Idiomatic Python: Распространение или выравнивание последовательностей?

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

Идея заключается в том, чтобы в конечном итоге с (плоской) последовательности узлов в дереве ,

Подход № 1: (распространяющиеся выходы)

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

подход # 2: (уплощение последовательности)

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

Первый подход кажется более чистым, но я чувствую себя странно, явно yield ИНГ каждый узел в поддереве на каждом уровне.

Второй подход немногословен и немного грязный, но это соответствует тому, что я хотел бы написать в Haskell:

traverse node = node : concatMap traverse (children node) 

Так что мой вопрос: Что лучше? Или я пропустил лучший третий вариант?

+0

описаний списков сделают этот пылесос. –

+0

Rafe: Напишите ответ и покажите мне! :-) – perimosocordiae

+1

Я бы хотел, чтобы это было понято в списке ... вам нужно было сгладить его в конце, верно? Насколько мне известно, решение «цепочки» замечательно. – delnan

ответ

4

[UPDATE] См PEP-380, этот выход все синтаксис доступен начиная с Python 3.3 в yield from:

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

@ THC4k, это хороший вопрос :-) Я c & p код из другого сценария, я думаю, что я пытался что-то в данный момент. Обновлено, оно должно работать без использования «списка».[oops, вы удалили свой комментарий?] – tokland

+0

да, когда вы его изменили;) –

+0

@ THC4k, да, извините, я никогда не доволен своими ответами, и я продолжаю их редактировать ;-) – tokland

3

Я бы с первым. Через пару раз вы получите распространение урожайности. :-)

1

Это вопрос мнения, поэтому все ответы будут только оценочными суждениями. Насколько я могу судить, нет никакого элегантного третьего пути.

Мое мнение таково, что первый способ побеждает руки. Это проще и понятнее - Python - это не Haskell, хотя он может делать некоторые функциональные вещи, и часто функциональный подход просто не выглядит таким аккуратным.

0

обход с положением узла:

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) 
Смежные вопросы