Python: Список мутаций на месте v. Копия списка мутаций - PullRequest
0 голосов
/ 04 августа 2020

Я пишу объект калькулятора, который оценивает строки, соответствующие int / float и операторам в «() * / +». Приведенные ниже функции берут список элементов, сформированный из строки, содержащей только целые числа / числа с плавающей запятой и операторы одного и того же ранга (здесь * и /), и оценивают выражение слева направо до тех пор, пока не останется больше операторов.

def execute(s):
    while "*" in s or "/" in s:
        temp = []
        for i in range(len(s)):
            if s[i] == "*" or s[i] == "/":
                res = perform(s[i-1], s[i], s[i+1])
                del temp[-1]
                temp.append(res)
                for e in s[i+2:]:
                    temp.append(e)
                s = temp
                break
            else:
                temp.append(s[i])
    return s

def execute1(s):  
    while len(s) > 1:
        while "*" in s or "/" in s:
            for i in range(len(s)):
                if s[i] == "*" or s[i] == "/":
                    res = perform(s[i-1], s[i], s[i+1])
                    s[i-1:i+2] = [None, None, res]
            s = [e for e in s if e != None]
    return s

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

Есть ли способ сделать это, чтобы не изменять список на месте и выполнять оценку только за один проход?

Ответы [ 2 ]

0 голосов
/ 04 августа 2020

, но возникли проблемы с определением правильного места в копии s для выполнения замен

Вы можете сделать это прямо в s, если хотите, вам просто нужно отслеживать, где находится текущий индекс (i ниже) после изменения списка:

import sys

def perform(a, op, b):
    if op == '*':
        return a * b
    elif op == '/':
        return a / b
    raise ValueError('unknown op:', op)

def next_operator(lst, start, operators='*/'):
    nextop = sys.maxsize
    for op in operators:
        try:
            nextop = min(nextop, lst.index(op, start))
        except ValueError:
            pass
    return nextop

def execute1(s):  
    i = 0
    while i := next_operator(s, i) != sys.maxsize:
        s[i-1:i+2] = [perform(*s[i-1:i+2])]
        i -= 1
    return s

вывод:

>>> execute1([5, '*', 3])
[15]
>>> execute1([2, "*", 3, "/", 4, "*", 5])
[7.5]
>>>
0 голосов
/ 04 августа 2020

Нет проблем с изменением списка, пока вы не повторяете его с помощью for-l oop, и даже тогда вы можете изменять список, если не меняете его размер.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...