How to find the length of a "filter" object in python
Asked Answered
T

6

93
>>> n = [1,2,3,4]

>>> filter(lambda x:x>3,n)
<filter object at 0x0000000002FDBBA8>

>>> len(filter(lambda x:x>3,n))
Traceback (most recent call last):
  File "<pyshell#3>", line 1, in <module>
    len(filter(lambda x:x>3,n))
TypeError: object of type 'filter' has no len()

I could not get the length of the list I got. So I tried saving it to a variable, like this...

>>> l = filter(lambda x:x>3,n)
>>> len(l)
Traceback (most recent call last):
  File "<pyshell#5>", line 1, in <module>
    len(l)
TypeError: object of type 'filter' has no len()

Instead of using a loop, is there any way to get the length of this?

Tepid answered 4/10, 2013 at 13:15 Comment(1)
There is no way to know how many objects a generator will yield before it yields them. If you care about optimization, you can use a priori information to speed things up - i.e. if you know that your list is sorted you can discard items below index(3).Allele
T
128

You have to iterate through the filter object somehow. One way is to convert it to a list:

l = list(filter(lambda x: x > 3, n))

len(l)  # <--

But that might defeat the point of using filter() in the first place, since you could do this more easily with a list comprehension:

l = [x for x in n if x > 3]

Again, len(l) will return the length.

Tompkins answered 4/10, 2013 at 13:18 Comment(3)
This is the simpliest way but not really the proper way. I prefer the answer of Al Hoo and tso . What a pity that python didn't internally support the reduce way!Dulciedulcify
This solution takes a lot of extra memory if n is quite large.Perineuritis
BEWARE that you cannot do next(l) no more cause de filter object has been "used" some how.Doited
C
34

This is an old question, but I think this question needs an answer using the map-reduce ideology. So here:

from functools import reduce

def ilen(iterable):
    return reduce(lambda sum, element: sum + 1, iterable, 0)

ilen(filter(lambda x: x > 3, n))

This is especially good if n doesn't fit in the computer memory.

Coaxial answered 4/6, 2017 at 7:14 Comment(4)
Is this faster than using len of a list iteration?Wrinkle
Not with python, but if you want to optimize some algorithm that needs the length of a filtered object, building a list to count the length is not the optimal way.Coaxial
Note that reduce was deliberately taken out of the standard library in Python 3.0 and greater. More details about why this was decided can be found here in this thread by Guido van Rossum: artima.com/weblogs/viewpost.jsp?thread=98196Huey
It seems that reduce it is going to be here for a while. check: docs.python.org/3.13/library/functools.html#functools.reduceTracheostomy
P
19

Converting a filter to a list will take extra memory, which may not be acceptable for large amounts of data. You can find length of the filter object without converting it to a list:

sum(1 for _ in filter(lambda x: x > 3, n))
Perineuritis answered 14/7, 2018 at 6:41 Comment(0)
R
17

Generally, filter and reduce are not pythonic.

@arshajii metioned this solution:

len([x for x in n if x > 3])

This is quite simple, but is not describing what you exactly want to do, and it makes a list that may use some additional memory. A better solution is using sum with generator:

sum(1 for x in n if x > 3)

(See more about generator here: https://www.python.org/dev/peps/pep-0289/#rationale)

However, sum with generator is actually slower in most cases because of the implementation (tested in CPython 3.6.4):

In [1]: %timeit len([1 for x in range(10000000)])
356 ms ± 17.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [2]: %timeit sum(1 for x in range(10000000))
676 ms ± 7.05 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
Reptant answered 14/6, 2018 at 8:16 Comment(0)
W
13

The docs for python 3 say it returns an iterator

"Construct an iterator from those elements of iterable for which function returns true."

In python 2 it returned a list: see here. You will need to iterate the filter object to find its length.

Winola answered 4/10, 2013 at 13:23 Comment(0)
D
0

Can be solved using more-itertools:

from more_itertools import ilen
f = filter(lambda x:x>3,n)
return ilen(f)

Note that ilen consumes the filter (you won't be able to use it afterwards - it will return an empty list)

Despair answered 11/9, 2022 at 12:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.