简体   繁体   中英

Python filter doesn't work as expected

I have the following Python code:

a = [1,2,3,'4','55',6]
filter(int,a)

The output is:

[1, 2, 3, '4', '55', 6]

filter() is supposed to remove the elements from the provided sequence which translate into false, and return only those elements which translate into true.

I expected the output to be:

[1,2,3,6]

since these are the only integers in my list. Am I missing something essential?

Use isinstance instead:

>>> a =[1,2,3,'4','55',6]
>>> filter(lambda x: isinstance(x, int),a)
[1, 2, 3, 6]

int will convert each object to integer and since all numbers/strings on the list are non-zero filter picks them all since they evaluate True in boolean context. Instead of that it seems that your goal is to pick objects that are already ints and that can be done with isinstance .

filter() calls the callable that it is given ( int ) with each item in the iterable and returns those that are Truthy. Since int('56') results in 56 , it is Truthy and is included in the results. You may want something like this:

filter(lambda x: isinstance(x, int), a)

or better:

[x for x in a if isinstance(x, int)]

I agree with @niemmi's and @zondo's solution ie

filter(lambda x: isinstance(x, int), a)

Now the question is why filter(int, a) didn't work ?

Filter ultimately call function(val) and if this returns false then it filtered it out.

>>> int('4')  # Which is returning 4, and its true.
4

But if you call this,

>>> a =[1,2,3,'4','0',6]
>>> filter(int, a)
[1,2,3,4,6]

>>> a =[1,2,3,'4','55a',6]
>>> filter(int, a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: '55a'

Try this:

[x for x in a if isinstance(x, int)]

or

filter(lambda x: isinstance(x, int), a)

A bit longer way:

  • We create a function within which we create a child function.

  • The first function that is "isins" will take function called inside filter ie isinstance as an input.

  • The code then see that it's returning check function and replace isins(isinstance) with check.

  • Inside child function there is a check for 'True' and 'False' explicitly as bool 1 and 0 are treated in same was as True and Flase hence if we remove this filter then the list will contain numbers as well as bool values and if we put bool filter then 1's and 0's will also get filtered out.

  • Ultimately we do the check of func/isinstance to return only those values that are either int or float.

     def isins(func): def check(a): if str(a) not in ('True','False'): return (func(a,(int,float))) return check num_list = list(filter(isins(isinstance),a)) num_list
  • Below code also lets you input datatype explicitly.

     def isins(func,dt): def check(a): if str(a) not in ('True','False'): return (func(a,dt)) return check num_list = list(filter(isins(isinstance,(int,float)),a)) num_list

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM