Python过滤器/最大组合 - 检查空迭代器
Posted
技术标签:
【中文标题】Python过滤器/最大组合 - 检查空迭代器【英文标题】:Python filter / max combo - checking for empty iterator 【发布时间】:2011-04-25 19:03:24 【问题描述】:(使用 Python 3.1)
我知道对于测试迭代器是否为空的一般问题,这个问题已经被问过很多次了;显然,没有很好的解决方案(我猜是有原因的——迭代器在被要求返回下一个值之前并不知道它是否为空)。
不过,我有一个具体的例子,我希望我可以用它编写干净的 Pythonic 代码:
#lst is an arbitrary iterable
#f must return the smallest non-zero element, or return None if empty
def f(lst):
flt = filter(lambda x : x is not None and x != 0, lst)
if # somehow check that flt is empty
return None
return min(flt)
有没有更好的方法?
编辑:对不起,愚蠢的符号。函数的参数确实是任意可迭代的,而不是列表。
【问题讨论】:
是的。 ActiveState Python 3.1.2。itertools.c_c_c_c_c_COMBO_BREAKER()
【参考方案1】:
def f(lst):
flt = filter(lambda x : x is not None and x != 0, lst)
try:
return min(flt)
except ValueError:
return None
min
在序列为空时抛出 ValueError
。这遵循常见的“更容易请求宽恕”范式。
编辑:一个基于 reduce 的解决方案,没有例外
from functools import reduce
def f(lst):
flt = filter(lambda x : x is not None and x != 0, lst)
m = next(flt, None)
if m is None:
return None
return reduce(min, flt, m)
【讨论】:
我害怕ValueError
被其他东西而不是空列表提出。是否 100% 确定 min 在任何其他情况下都不会提高 ValueError
?另外,我可能需要用列表理解替换lst
;在那种情况下,我更害怕ValueError
由我自己的代码在列表理解中引起。
@max,我并不肯定,因为 Python 不擅长记录这类事情。但是,flt
应该始终是可迭代的。即使不是这样,如果您传递了错误类型的参数,它看起来就像min
抛出TypeError
。我想不出min
本身会抛出什么别的东西。现在,目前看起来lst
是一个列表。如果不是,那肯定是一个误导性的名称。在这种情况下,您不必担心列表理解,因为它在f
开始之前就已经完成了。如果是生成器理解,那就有点复杂了。
如果 Python 不记录这种类型的东西,感觉有点危险。毕竟,我正在为宇宙飞船上的生命支持模块编写软件,将人类定居者带到……啊,没关系:) 但我不喜欢依赖内置的特定异常类型,除非它有大量文档。
如果我把它列出来,我想还不如明确检查它的长度。
@max,我已经发布了一个避免列表和异常的解决方案。【参考方案2】:
def f(lst):
# if you want the exact same filtering as the original, you could use
# lst = [item for item in lst if (item is not None and item != 0)]
lst = [item for item in lst if item]
if lst: return min(lst)
else: return None
列表推导仅允许不评估为布尔值 false 的项目(过滤掉 0 和无)
一个空列表,即 [] 将评估为 False,因此“if lst:”只会在列表有项目时触发
【讨论】:
如果你愿意,用更严格的集合替换“if item”很简单,但是我不认为“”,[],set(),tuple()无论如何都算作非零; ) 看起来他要使用 min() 调用 NUMBERS。【参考方案3】:你也可以使用reduce表达式return reduce(lambda a,b: a<b and a or b,x) or None
【讨论】:
这没有回答 OP 的问题,这仍然存在空迭代器或空列表的问题。【参考方案4】:如果你只是想检查过滤器的返回是否为空,你可以这样做(Python3)
len(list(filter(lambda e : e == 2, [1,2,3])))
但是请注意,如果你这个测试两次,过滤器是一个生成器,第二次,你会收到不同的结果:
len(list(filter(lambda e : e == 2, [1,2,3])))
len(list(filter(lambda e : e == 2, [1,2,3])))
>>> 1
>>> 1
但是:
f = filter(lambda e : e == 2, [1,2,3])
len(list(f))
len(list(f))
>>> 1
>>> 0
【讨论】:
转换为列表只是为了查看迭代器是否为空既低效又冗长。【参考方案5】:t = [1,2,3]
if any(filter(lambda x: x == 10, t)):
print("found 10")
【讨论】:
如果您给出的答案不是给出的答案,请说明它与其他人的不同之处。以上是关于Python过滤器/最大组合 - 检查空迭代器的主要内容,如果未能解决你的问题,请参考以下文章