Python:简化多个if语句

3

我有一个函数,它遍历一棵树,并将元素作为列表返回。是否有简化所有if语句的方法在treeToList::traverse中,因为它看起来有点冗余?

#!/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']

1
在重构请求中附带测试套件会得到加分 :) - Pavel Anossov
4个回答

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

但是它会建立许多中间列表。


+1. 这正是我在上个段落中所要表达的意思。我觉得用Python写比用英语写更容易。(这样理解起来肯定更容易。) - abarnert

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

虽然并不是真正的简化,但在某种程度上更加整洁,所以+1。 - isedev
我认为这里每次遍历的实现比原始问题更清晰。但是,对于这段代码来说,确实没有太多可以澄清的。 - Bill Lynch
如果你真的想要:(preorder_traversal, inorder_traversal, postorder_traversal)[order](node) 这样做会让代码“更简单”……但显然可读性会降低。 - abarnert

2

我认为在不重新组织算法的情况下,很难消除三个if order语句。 ret.append发生的位置取决于值,因此你基本上必须检查它所有三次,以某种方式。

但是有一种明显的方法可以重新组织事物以删除几个if

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语句而不是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,但我认为结果并不比之前更易阅读或理解...
实际上,使其更易于阅读和理解的方法可能是切换到函数式算法(递归可变算法很难思考)...但这只会使三个if主体更大,而不能摆脱它们。

0

尝试类似这样的东西

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

细节问题

您应该将您的条件分布在多行中。

if cond:
    pass

替代

if cond: pass

在比较是否为None时,也可以考虑使用isis not而不是==!=


1
与之前的答案相同问题(现已删除):条件的顺序很重要...您建议的更改了那个顺序。 - isedev
@isedev,+1。你说得对,我会保留它,这样别人就不会犯同样的错误了。 - John
好的,无可厚非,我不能移除-1(不是我干的)。 - isedev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接