介绍
Python内置的filter()
函数能够从可迭代对象(如字典、列表)中筛选某些元素,并生成一个新的迭代器。可迭代对象是一个可以被“遍历”的Python对象,也就是说,它将按顺序返回各元素,这样我们就可以在fo
r循环中使用它。
filter()
函数的基本语法是:
filter(function, iterable)
返回一个可迭代的filter对象,可以使用list()
函数将其转化为列表,这个列表包含过滤器对象中返回的所有的项。
filter()
函数所提供的过滤方法,通常比用列表解析更有效,特别是当我们处理更大的数据集时。例如,列表解析会生成一个新列表,这会增加该处理的运行时间。当列表解析执行完毕它的表达式后,内存中会有两个列表。但是,filter()
将生成一个简单的对象,该对象包含对原始列表的引用、提供的函数以及原始列表中位置的索引,这样操作占用的内存更少。
下面介绍filter()
的四种不同用法:
在filter()
中使用特殊函数
filter()
的第一个参数是一个函数,用它来决定第二个参数所引用的可迭代对象中的每一项的去留。此函数被调用后,当返回False
时,第二个参数中的可迭代对象里面相应的值就会被删除。针对这个函数,可以是一个普通函数,也可以使用lambda
函数,特别是当表达式不那么复杂的时候。
下面是filter()
中使用lambda
函数的方法:
filter(lambda item: item[] expression, iterable)
将下面的列表,用于lambda
函数,根据lambda
函数表达式筛选列表中的元素。
creature_names = ['Sammy', 'Ashley', 'Jo', 'Olly', 'Jackie', 'Charlie']
要筛选此列表以元音开头的水族馆生物的名称,lambda
函数如下:
print(list(filter(lambda x: x[0].lower() in 'aeiou', creature_names)))
在这里,我们将列表中的一个项声明为x
,并以x[0]
的方式访问每个字符串的第一个字符,并且要将字母转化为小写,以确保将字母与'aeiou'
中的字符匹配。
最后,要提供可迭代对向creature_name
。与上一节一样,用list()
将返回结果转化为列表表。
输出如下:
['Ashley', 'Olly']
当然,写一个函数,也能够实现类似的结果:
creature_names = ['Sammy', 'Ashley', 'Jo', 'Olly', 'Jackie', 'Charlie']
def names_vowels(x):
return x[0].lower() in 'aeiou'
filtered_names = filter(names_vowels, creature_names)
print(list(filtered_names))
在names_vowels
函数中用一个表达式,完成了对creature_names
的过滤。
同样,输出如下:
['Ashley', 'Olly']
总的来说,在filter()
函数中使用lambda函数得到的结果与使用常规函数得到的结果相同。如果所要过滤数据更复杂了,还可能要使用正则表达式,这可能会提高代码的可读性。
在filter()
中使用None
我们也可以将None
作为filter()
的第一个参数,让迭代器过滤掉Python中布尔值是False
的对象,比如长度为0的对象(如空列表或空字符串)或在数字上等于0的对象。
下面的示例中要过滤一个列表,去掉其中布尔值是False
的元素。
aquarium_tanks = [11, False, 18, 21, "", 12, 34, 0, [], {}]
filtered_tanks = filter(None, aquarium_tanks)
这段代码在filter()
中使用了None,并将aquarium_tanks
列表作为可迭代项传入。将None
作为第一个参数,可以检查列表中的元素是否为False
。
print(list(filtered_tanks))
然后再将filtered_tanks
传给list()
函数,这样就得到了一个列表。
从输出结果中可以看出,我们得到了想要的整数,那些布尔值是False
的项都筛选掉了。
[11, 25, 18, 21, 12, 34]
注意:如果不使用list()
并打印filtered_tanks
,将得到一个类似于<filter object at 0x7fafd5903240>
这样的filter对象。filter对象是可迭代的,因此我们可以使用for循环它,也可以使用list()
将其转换为列表。
借助None
,用filter()
快速地从列表中删除被认为False
的项。
将filter()
用于复杂场景
对于复杂的数据结构,filter()
也可以胜任,例如,有一个由字典组成的列表,我们不仅要遍历列表中的每项(字典), 还可能要遍历字典中的每个键值对,以便得到所有的数据。
举个例子,假设我们有水族馆里每种生物的一个列表以及每种生物的不同细节,用下面的列表显示此数据。
aquarium_creatures = [
{"name": "sammy", "species": "shark", "tank number": "11", "type": "fish"},
{"name": "ashley", "species": "crab", "tank number": "25", "type": "shellfish"},
{"name": "jo", "species": "guppy", "tank number": "18", "type": "fish"},
{"name": "jackie", "species": "lobster", "tank number": "21", "type": "shellfish"},
{"name": "charlie", "species": "clownfish", "tank number": "12", "type": "fish"},
{"name": "olly", "species": "green turtle", "tank number": "34", "type": "turtle"}
]
下面就写一个函数,用这个函数来过滤这些数据。为了让filter()
访问每个字典和字典中的每个元素,这需要构造一个嵌套函数,如下所示:
def filter_set(aquarium_creatures, search_string):
def iterator_func(x):
for v in x.values():
if search_string in v:
return True
return False
return filter(iterator_func, aquarium_creatures)
定义filter_set()
函数,以aquarium_creatures
和search_string
作为参数。在filter_set()
中,将内部函数iterator_func()
作为filter()
的参数。filter_set()
函数将返回由filter()
生成的迭代器。
iterator_func()
以x
作为参数,它代表列表中的一个项(即单个字典)。
接下来,for
循环访问字典中每个键值对,然后使用条件语句检查search_string
是键值对中的值。
iterator_func
函数作为filter
函数的参数对象,用它对迭代对象进行筛选。例如:用filter_set()
搜索字符串:
filtered_records = filter_set(aquarium_creatures, "2")
一旦函数执行完毕,过滤器对象存储在filtered_records
变量中,我们将其转换为一个列表并打印:
print(list(filtered_records))
输出内容:
[{'name': 'ashley', 'species': 'crab', 'tank number': '25', 'type': 'shellfish'}, {'name': 'jackie', 'species': 'lobster', 'tank number': '21', 'type': 'shellfish'}, {'name': 'charlie', 'species': 'clownfish', 'tank number': '12', 'type': 'fish'}]
刚才的示例中,我们用filter()
实现了在字典组成的列表中过滤制定字符。
结论
本文中列举了filter()
函数的不同使用方法。如果你打算深入了解,请阅读《Python大学实用教程》(电子工业出版社)一书,这是针对零起点读者,并特别注重工程实践的不可多得的读物。