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过滤器/最大组合 - 检查空迭代器的主要内容,如果未能解决你的问题,请参考以下文章

python模块分析之itertools

Python中迭代器&生成器的“奇技淫巧“

Python中迭代器&生成器的“奇技淫巧“

为啥 C++ 字符串迭代器不检查错误?

python 过滤器(函数,迭代器)

itertools常用函数