Python:访问嵌套列表中最内容列表的元素

时间:2016-11-23 22:35:28

标签: python

如果我有如下的嵌套列表,我如何首先访问['*', '5', '8'](最里面的列表),以便我可以执行乘法,然后转到下一个最里面的列表,即['*',[result_from_previous_step],'9'],依此类推,直到外部找到最多的名单

['*', ['*', ['*', '5', '8'], '9'], '10']

这似乎有点像向我评估树,但是以自下而上的方式

4 个答案:

答案 0 :(得分:3)

最直接的解决方案是编写一个递归函数,调用自身来评估内部表达式。

# helper function to parse strings where necessary
def intorfloat(number):
    if not isinstance(number, str):   # already parsed
       return number
    try:
        return int(number)
    except ValueError:
        return float(number)

# evaluates a simple expression (no subexpressions)
def evaluate2(operation, operand1, operand2):
    operand1, operand2 = intorfloat(operand1), intorfloat(operand2)
    if operation == "*":
        return operand1 * operand2
    elif operation == "+":
        return operand1 + operand2
    elif operation == "/":
        # keep the result an int if possible
        result1 = operand1 // operand2
        result2 = float(operand1) / operand2
        return result1 if result1 == result2 else result2
    elif operation == "-":
        return operand1 - operand2

# recursively evaluate an expression with subexpressions
def evaluate(expression):
    operation, operand1, operand2 = expression
    if isinstance(operand1, list):
        operand1 = evaluate(operand1)
    if isinstance(operand1, list):
        operand2 = evaluate(operand2)
    return evaluate2(operation, operand1, operand2)

迭代解决方案也是可能的;优点是您可以评估任何深度的表达式。在这个版本中,我们继续下降到子列表,直到我们找到一个叶子:一个没有任何子表达式的表达式。然后我们评估叶子并用它的结果替换它,并从头开始。最终,顶级表达式没有子表达式。

该算法实际上修改了表达式,反复简化表达式,直到评估它为止。 (递归解决方案不会修改表达式。)

如果表达式很深,我们可能会进行大量不必要的遍历来重复查找叶节点。我们可以创建一个堆栈来允许我们回溯,而不是每次都从顶部开始,但我们也可以在那时使用递归解决方案。

# uses intorfloat() and evaluate2() functions previously shown

def evaluate(expression):
    while isinstance(expression[1], list) or isinstance(expression[2], list):
        current = expression
        container = None
        while True:         # find a leaf node
            operation, operand1, operand2 = current
            if isinstance(operand1, list):
               container, slot = current, 1
               current = operand1
            elif isinstance(operand2, list):
                container, slot = current, 2
                current = operand2
            else:
                break
        if container:
            container[slot] = evaluate2(*current)
    return evaluate2(*expression)

print evaluate(['*', ['*', ['*', '5', '8'], '9'], '10'])   # 3600

答案 1 :(得分:1)

这是您问题的粗略解决方案

l = ['*', ['*', ['*', '5', '8'], '9'], '10']

def islist(l):
    try:
        l.append
        return True
    except AttributeError:
        return False

def reduce(l):
    if islist(l):
        return recurse(l)
    else:
        return l

def recurse(l):
    if not islist(l):
        return l

    first = reduce(l[0])
    second = reduce(l[1])
    third = reduce(l[2])

    return "({} {} {})".format(second, first, third)

print recurse(l)

使用递归。 Python不是实现递归算法的最佳语言,像Erlang这样的纯函数语言在这些主题上更强大。

主要问题是递归调用的最大次数和内存占用,但对于这么小的列表,这是有效的。

您可以遇到的一个问题是如何区分列表和其他内容,这并非如此简单。您可以像我一样使用isinstance()或try / except。在这种情况下,集合模块没有用处,因为列表和字符串都是序列。

答案 2 :(得分:0)

您可以使用eval创建自定义递归函数,以实现此目的:

def perform_operation(my_list):
    temp_list = []
    for item in my_list:
        if isinstance(item, list):
            item = perform_operation(item)
        temp_list.append(item)
    return eval('{} {} {}'.format(temp_list[1], temp_list[0], temp_list[2]))

示例运行:

>>> my_list = ['*', ['*', ['*', '5', '8'], '9'], '10']
>>> perform_operation(my_list)
3600

注意:使用eval是不安全的,因为它执行字符串的内容,无论它有什么。所以,请确保你传递给它的是什么

答案 3 :(得分:0)

这是一个“更多Pythonic”,更容易扩展的版本,上面提到的那种。它也不假设数字是整数。

import operator
def evaluate(expression):
    if isinstance(expression, str):
        return float(expression)

    op, operand1, operand2 = expression
    ops = {"*" : operator.mul, 
           "+" : operator.add, 
           "/" : operator.truediv, 
           "-" : operator.sub}
    return ops[op](evaluate(operand1), evaluate(operand2))    

evaluate(['*', ['*', ['*', '5', '8'], '9'], '10'])