百木园-与人分享,
就是让自己快乐。

1.16 过滤序列元素

问题描述

你有一个数据序列,想利用一些规则从中提取出需要的值或是缩短的序列。

解决方案

最简答的过滤序列元素的方法就是使用列表推导式。比如:

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(),当你需要通过另一个相关联的序列来过滤某个序列时,可以用到它。

来源:https://www.cnblogs.com/L999C/p/15749290.html
图文来源于网络,如有侵权请联系删除。

未经允许不得转载:百木园 » 1.16 过滤序列元素

相关推荐

  • 暂无文章