#python
#python
Вопрос:
У меня возникла проблема при использовании функции filter в цикле for. 2 случая похожи, но результат разный:
nums = list(range(1, 15))
nums = filter(lambda x: x % 2 == 0, nums)
nums = filter(lambda x: x % 3 == 0, nums)
nums = filter(lambda x: x % 4 == 0, nums)
print(list(nums))
>>> [12]
и
nums = list(range(1, 15))
for i in range(2, 5):
nums = filter(lambda x: x % i == 0, nums)
print(list(nums))
>>> [4, 8, 12]
Если я преобразую объект фильтра в список, результат будет правильным.
nums = list(range(1, 15))
for i in range(2, 5):
nums = list(filter(lambda x: x % i == 0, nums))
print(nums)
>>> [12]
Есть ли какое-либо решение, использующее цикл for без преобразования объекта фильтра в список в этом случае?
Комментарии:
1.
nums = filter(lambda x, i=i: x % i == 0, nums)
Ответ №1:
filter
возвращает генератор, поэтому вы получаете список только после передачи генератора list()
, который принимает все сгенерированные элементы и возвращает их в виде списка.
Способ получить то, что вы хотите, без filter()
использования for
:
nums = list(range(1, 15))
result = [x for x in nums for i n range(2, 5) if x % i == 0]
Это называется пониманием списка, и это очень эффективный и понятный способ построения подобного списка.
Комментарии:
1. Если он отвечает на ваш вопрос, пожалуйста, примите ответ с пометкой, чтобы вопрос отображался как ответ при поиске. Если вы искали другое решение, не стесняйтесь, дайте мне знать, что вам не нравится в этом.
2. Понимание списка — один из возможных способов, но я хотел бы понять разницу между 2 случаями, спасибо
Ответ №2:
Фильтр — это генератор. Поэтому он использует отложенное вычисление выражения. Из документации:
Переменные, используемые в выражении генератора, вычисляются лениво, когда
__next__()
метод вызывается для объекта генератора (таким же образом, как и обычные генераторы).
Это означает, что лямбда-выражение вычисляется при вызове list(nums)
, потому что оно вызывает __next__()
метод под капотом.
Итак, во втором примере он будет (я думаю) фильтровать 3 раза всегда с разделителем 4:
nums = filter(lambda x: x % 4 == 0)
nums = filter(lambda x: x % 4 == 0)
nums = filter(lambda x: x % 4 == 0)
Возможно, этот фрагмент кода дает вам лучшее понимание. Обратите внимание, что выражение вычисляется при list()
вызове. Как вы можете видеть, цикл здесь не изменяет результат. Использование переменной i
имеет значение:
nums = list(range(1, 15))
i = 2
nums = filter(lambda x: x % i == 0, nums)
i = 3
nums = filter(lambda x: x % i == 0, nums)
i = 4
nums = filter(lambda x: x % i == 0, nums)
print(list(nums)) # here i==4
### [4, 8, 12]
nums = list(range(1, 50))
for i in range(2, 5):
nums = filter(lambda x: x % i == 0, nums)
i = 11
print(list(nums)) # here i==11
### [11, 22, 33, 44]
Еще одно решение:
def f(x):
for i in range(2, 5):
if x % i != 0:
return False
return True
nums = list(range(1, 15))
nums = filter(f, nums)
print(list(nums))