2013-03-20 2 views
3

У меня есть функция, которая пересекает дерево и возвращает элементы в виде списка. Есть ли способ упростить все инструкции if в treeToList::traverse, потому что он выглядит как лишний?Python: упростить многие операторы if

#!/usr/bin/python 

def enum(**enums): 
    return type('Enum',(), enums) 

Order = enum(PREORDER=0, INORDER=1, POSTORDER=2) 
def treeToList(root, order=Order.INORDER): 
    ret = list() 
    def traverse(node, order): 
    if order == Order.PREORDER: ret.append(node.data) 
    if node.right != None: traverse(node.right, order) 
    if order == Order.INORDER: ret.append(node.data) 
    if node.down != None: traverse(node.down, order) 
    if order == Order.POSTORDER: ret.append(node.data) 
    traverse(root, order) 
    return ret 

class node: 
    def __init__(self, data=None): 
    self.data = data 
    self.down = None 
    self.right = None 

if __name__ == '__main__': 
    root = node('F') 
    root.right = node('B') 
    root.down = node('G') 
    root.right.right = node('A') 
    root.right.down = node('D') 
    root.down.down = node('I') 
    root.right.down.right = node('C') 
    root.right.down.down = node('E') 
    root.down.down.right = node('H') 

    print treeToList(root, Order.PREORDER) 
    print treeToList(root, Order.INORDER) 
    print treeToList(root, Order.POSTORDER) 

Выход

['F', 'B', 'A', 'D', 'C', 'E', 'G', 'I', 'H'] 
['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'] 
['A', 'C', 'E', 'D', 'B', 'H', 'I', 'G', 'F'] 
+0

короткий ответ: нет :) – isedev

+1

+1 для включения тестового набора с запросом на рефакторинг :) –

ответ

5

Ну, если вы избавитесь от закрытия .. чистая функция, вероятно, более ясное:

def treeToList(node, order=Order.INORDER): 
    if node is None: 
     return [] 

    right = treeToList(node.right, order) 
    down = treeToList(node.down, order) 
    current = [node.data] 

    if order == Order.PREORDER: 
     return current + right + down 

    if order == Order.INORDER: 
     return right + current + down 

    if order == Order.POSTORDER: 
     return right + down + current 

но строит конечно, много промежуточных списков.

+0

+1. Это именно то, что я имел в виду под моим последним абзацем. Я думаю, что писать на Python было проще, чем на английском. (Это, конечно, легче понять.) – abarnert

0

Попробуйте что-то вроде

if order in (Order.PREORDER, Order.INORDER, ...): 
    ret.append(node.data) 

Nitpicks

Вы должны иметь свои условия на нескольких линиях

if cond: 
    pass 

вместо

if cond: pass 

также рассмотреть возможность использования is и is not при сравнении с None вместо == и !=.

+1

та же проблема, что и предыдущая (теперь удалена) ответ: порядок условий ВАЖНО ...что вы предлагаете изменить этот порядок. – isedev

+0

@isedev, +1 вы правы, я оставлю это, чтобы другие не совершали ту же ошибку. – John

+0

справедливо, не может удалить -1 (не был я). – isedev

2

Единственное, что приходит на ум это:

def treeToList(root, order=Order.INORDER): 
    ret = list() 
    def inorder_traversal(node): 
     if node is not None: 
      inorder_traversal(node.right) 
      ret.append(node.data) 
      inorder_traversal(node.down) 

    def preorder_traversal(node): 
     if node is not None: 
      ret.append(node.data) 
      preorder_traversal(node.right) 
      preorder_traversal(node.down) 

    def postorder_traversal(node): 
     if node is not None: 
      postorder_traversal(node.right) 
      postorder_traversal(node.down) 
      ret.append(node.data) 

    if order == Order.PREORDER: 
     preorder_traversal(node) 
    elif order == Order.INORDER: 
     inorder_traversal(node) 
    else: 
     postorder_traversal(node) 

    return ret 
+0

не очень упрощение, хотя ... но аккуратный в некотором смысле, так +1. – isedev

+0

Я бы сказал, что более ясно, что каждый обход выполняется здесь правильно, чем в исходном вопросе. Но да, не так много можно сделать, чтобы прояснить этот код. –

+0

Если вы действительно хотите: '(preorder_traversal, inorder_traversal, postorder_traversal) [order] (node)' фактически сделает это «более простым» ... но, очевидно, менее читаемым. – abarnert

2

Я не думаю, что есть хороший способ устранить три заявления if order без реорганизации алгоритма. Позиция, на которой происходит ret.append, зависит от значения, поэтому вам в значительной степени нужно проверить все три раза, так или иначе.

Но есть один очевидный способ реорганизовать вещи, чтобы удалить пару if S:

def traverse(node, order): 
    if node is None: return 
    if order == Order.PREORDER: ret.append(node.data) 
    traverse(node.right, order) 
    if order == Order.INORDER: ret.append(node.data) 
    traverse(node.down, order) 
    if order == Order.POSTORDER: ret.append(node.data) 

Конечно, это одна строка длиннее, но это всего лишь 4 if s вместо 6.

Другая возможность изменить положение вещей для отслеживания всех трех позиций и вставить в соответствующее положение после факта:

def traverse(node, order): 
    if node is None: return 
    prepos = len(ret) 
    traverse(node.right, order) 
    inpos = len(ret) 
    traverse(node.down, order) 
    postpos = len(ret) 
    pos = (prepos, inpos, postpos)[order] 
    ret[pos:pos+1] = node.data 

Это удаляет все if с, но я не думаю, что результат будет проще читать или понимать ...

На самом деле, чтобы облегчить чтение и понимание, возможно, это переход на функциональный алгоритм (рекурсивные изменчивые алгоритмы редко бывают интересными для размышлений) ... но это только собирается сделать три тела более крупными, а не избавиться от них.

Смежные вопросы