Избегайте вычисления одного и того же выражения дважды в понимании списка

Я использую функцию в понимании списка и функцию if:

new_list = [f(x) for x in old_list if f(x) !=0]

Меня раздражает, что выражение f(x) вычисляется дважды в каждом цикле.

Есть ли способ сделать это более чистым способом? Что-то вроде сохранения значения или включения оператора if в начале понимания списка.

4 ответа

Решение

Вычислите результаты заранее и переберите их

new_list = [x for x in map(f, old_list) if x !=0]

Более того, поскольку map вычисляет результат для элемента при обращении к элементу, это всего лишь один цикл.

Вы можете использовать выражение генератора (чтобы избежать создания ненужного списка) внутри вашего списка:

new_list = [fx for fx in (f(x) for x in old_list) if fx != 0]

начиная с Python 3.8 вы сможете сделать это:

new_list = [fx for x in old_list if (fx := f(x)) != 0]

В Python 3.8 у нас будет "оператор моржа", и мы сможем это сделать!

[y for x in old_list if (y := f(x)) != 0]

Вы могли бы использовать filter чтобы удалить результаты:

def f (x):
  return x * 2

old_list = [0, 1, 2, 3]

new_list = filter(lambda x: x != 0, [f(x) for x in old_list])

for x in new_list:
  print(x)

Посмотрите, как это работает здесь.

В качестве альтернативы вы можете запомнить функцию, чтобы избежать необходимости вычислять один и тот же результат дважды:

def f (x):
  return x * 2

def memoize(f):
    memo = {}
    def helper(x):
        if x not in memo:
            print("Computing result for %s" % x)        
            memo[x] = f(x)
        return memo[x]
    return helper

memF = memoize(f)

old_list = [0, 1, 2, 3]

new_list = [memF(x) for x in old_list if memF(x) != 0]

for x in new_list:
  print(x)

Который доступен здесь.

Другие вопросы по тегам