问题描述
你有一个资料序列,想利用一些规则从中提取出需要的值或是缩短的序列,
解决方案
最简答的过滤序列元素的方法就是使用串列推导式,比如:
mylist = [1, 4, -5, 10, -7, 2, 3, -1]
res = [n for n in mylist if n > 0]
"""
res = [1, 4, 10, 2, 3]
"""
如果你对存储器比较敏感,可以使用生成器表达式迭代产生过滤的元素,比如:
gen = (n for n in mylist if n > 0)
print(gen)
""" 输出结果:
<generator object <genexpr> at 0x000001E4C8796CF0>
"""
for i in gen:
print(i)
""" 输出结果:
1
4
10
2
3
"""
有时候过滤规则比较复杂,不能简单的在串列推导式或者生成器表达式中表达出来,比如,过滤的时候需要处理一些例外或其他复杂情况,这时候你可以将过滤代码封装到一个函式中,然后使用内置函式filter()
,例如:
values = ['1', '2', '-3', '-', '4', 'N/A', '5']
def is_int(v):
try:
x = int(v)
return True
except ValueError:
return False
res = list(filter(is_int, values))
print(res)
"""输出结果:
['1', '2', '-3', '4', '5']
"""
需要注意,filter()
函式创建的是一个迭代器,
讨论
由官方档案的介绍,串列推导式的方括号内包含以下内容:一个表达式,后面为一个for子句,然后是零个或多个for或if子句,结果是由表达式依据for和if子句求值计算而得出一个新串列,清楚了概念,再看下面几个例子,
串列推导式和生成器表达式通常是过滤资料最简单的方式,它们还能在过滤的时候转换资料,例如:
import math
mylist = [1, 4, -5, 10, -7, 2, 3, -1]
res = [math.sqrt(n) for n in mylist if n > 0]
print(res)
"""输出结果:
[1.0, 2.0, 3.1622776601683795, 1.4142135623730951, 1.7320508075688772]
"""
过滤操作的一个变种是将不符合条件的值用新的值替代,而不是丢掉它们,比如,你不仅想找到正数,还想将不是正数的数换成0,通过将过滤条件放到条件表达式中,就可以很容易地解决这个问题:
res = [n if n > 0 else 0 for n in mylist]
"""
res = [1, 4, 0, 10, 0, 2, 3, 0]
"""
res = [n if n < 0 else 0 for n in mylist]
"""
res = [0, 0, -5, 0, -7, 0, 0, -1]
"""
另外一个值得关注的过滤工具就是itertools.compress()
,它以一个iterable
物件和一个相对应的Boolean
选择器序列作为输入自变量,然后输出iterable
物件中对应选择器为True
的元素,当你需要用另一个相关联的序列来过滤某个序列的时候,这个函式是非常有用的,例如,你有如下两组资料:
addresses = [
'5412 N CLARK',
'5148 N CLARK',
'5800 E 58TH',
'2122 N CLARK',
'5645 N RAVENSWOOD',
'1060 W ADDISON',
'4801 N BROADWAY',
'1039 W GRANVILLE',
]
counts = [ 0, 3, 10, 4, 1, 7, 6, 1]
这两个序列的元素个数是相等的,也就是它们的元素可以是一一对应的关系,现在你想将对应count值大于5的地址值全部输出,那么你可以:
for itertools import compress
more5 = [n > 5 for n in counts]
print(more5)
"""输出结果:
[False, False, True, False, False, True, True, False]
"""
res = list(compress(addresses, more5))
print(res)
"""输出结果:
['5800 E 58TH', '1060 W ADDISON', '4801 N BROADWAY']
"""
这里的关键点在于先创建一个Boolean
序列,指示哪些元素符合条件,然后compress()
函式根据这个序列去选择输出对应位置为True
的元素,
和filter()
函式类似,compress()
回传的也是一个迭代器,因此,如果你想得到一个串列,那么你需要使用list()
来将结果转换为串列型别,
总结
本节介绍了过滤序列元素的几种方法,
最简单的方法就是利用串列推导式,如果你对存储器使用有要求,可以改用生成器表达式,如果过滤规则过于复杂,无法在串列推导式或生成器表达式中表达出来,可以使用内置函式filter()
,
另外还介绍了一个过滤工具itertools.compress()
,当你需要通过另一个相关联的序列来过滤某个序列时,可以用到它,
0 评论