1

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?

1
  • 1
    nums = filter(lambda x, i=i: x % i == 0, nums) Commented Jan 4, 2021 at 22:22

2 Answers 2

4

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.

Sign up to request clarification or add additional context in comments.

2 Comments

If it answers your question, please accept the answer with the checkmark, so that the question shows up as answered in searches. If you were looking for a different solution, feel free to let me know what you don't like about this one.
List comprehension is one possible way but I would like to understand the difference between 2 cases, thank you
1

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.