如果我有如下的嵌套列表,我如何首先访问['*', '5', '8']
(最里面的列表),以便我可以执行乘法,然后转到下一个最里面的列表,即['*',[result_from_previous_step],'9']
,依此类推,直到外部找到最多的名单
['*', ['*', ['*', '5', '8'], '9'], '10']
这似乎有点像向我评估树,但是以自下而上的方式
答案 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'])