2016-11-23 6 views
0

Если у меня есть вложенный список, как показано ниже, как мне получить первый доступ к ['*', '5', '8'] (самый внутренний список), чтобы я мог выполнить умножение, а затем перейти к следующему самому сокровенному списку, т.е. ['*',[result_from_previous_step],'9'] и так далее на до самой внешней список найденPython: доступ к элементам внутреннего большинства списков во вложенных списках

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

Это кажется, что некоторые, что, как оценивать дерево для меня, но в нижней части до моды

+0

Что вы пытаетесь достичь? – ettanany

+0

Это точно так же, как оценка дерева. Вам просто нужно определить на каждом шаге, если операнды являются деревьями и рекурсивно оценивают их.Если они не деревья (они листья), то вы пропустите оценку этой ветви и просто оцените выражение. – mgilson

+0

@ettanany Я не был уверен, как это сделать, но, как я уже сказал в своем вопросе, думал о достижении этого, оценивая дерево. – jack

ответ

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 
+0

Также есть модуль 'operator' для выполнения математических операций. –

+2

Да, вы могли бы написать этот код, используя словарь и функции 'operator'; Я просто не хотел слишком сильно его обманывать. :-) – kindall

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 не безопасно, так как он выполняет содержание строки, независимо от того, что она имеет. Так что, будьте уверены относительно того, что вы передаете ему

0

Это грубое решение вашей проблемы

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, как я. Модуль коллекций не так полезен в этом случае, потому что оба списка и строки являются последовательностями.

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'])