Reputation: 13
I got an issue when using filter-function in for loop. 2 cases are similar, but the result is different:
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]
and
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]
If I convert filter-object to list, the result is correct.
nums = list(range(1, 15))
for i in range(2, 5):
nums = list(filter(lambda x: x % i == 0, nums))
print(nums)
>>> [12]
Is there any solution using for loop without converting filter object to list in this case?
Upvotes: 1
Views: 3627
Reputation: 173
Filter is generator. Therefore it uses lazy evaluation of expression. From documentation:
Variables used in the generator expression are evaluated lazily when the
__next__()
method is called for the generator object (in the same fashion as normal generators).
It means that lambda expression is evaluated when you call list(nums)
because it calls __next__()
method under the hood.
So in your second example it will (I guess) filter 3 times always with divider 4:
nums = filter(lambda x: x % 4 == 0)
nums = filter(lambda x: x % 4 == 0)
nums = filter(lambda x: x % 4 == 0)
Maybe that piece of code gives you better understanding. Notice that expression is evaluated when list()
is called. As you can see, loop here doesn't change the result. Using variable i
makes the difference:
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]
One more solution:
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))
Upvotes: 1
Reputation: 31329
filter
returns a generator, which is why you only obtain a list after passing the generator to list()
, which takes all the elements generated and returns them in a list.
A way to get what you want without filter()
and using for
:
nums = list(range(1, 15))
result = [x for x in nums for i n range(2, 5) if x % i == 0]
This is called a list comprehension and it's very efficient and readable way of constructing a list like this.
Upvotes: 4