带有回调的Python中的any()函数


74

Python标准库定义了一个any()函数

如果iterable的任何元素为true,则返回True。如果iterable为空,则返回False。

仅检查元素的取值为True。我希望它能够因此指定一个回调来告诉某个元素是否符合要求,例如:

any([1, 2, 'joe'], lambda e: isinstance(e, int) and e > 0)

4
如果需要,您可以随时使用,any(map(lambda:..., [...]))但是使用生成器理解更为惯用。
Thomas Ahle 2013年

Answers:


124

怎么样:

>>> any(isinstance(e, int) and e > 0 for e in [1,2,'joe'])
True

all()当然也可以使用:

>>> all(isinstance(e, int) and e > 0 for e in [1,2,'joe'])
False

6
此类函数的问题是否是它会首先创建一个完整的布尔列表,然后检查一个1是否为真,这不是问题吗?发现第一个有效实例后是否停止?
乔尔·哈克斯

6
@JoelHarkes只要您不将Iterable包装在[]或中list(),它就应该使用生成器并根据需要工作。
伊恩·亨特

19

当任何条件为True时,any函数将返回True。

>>> any(isinstance(e, int) and e > 0 for e in [0 ,0, 1])
True # Returns True because 1 is greater than 0.


>>> any(isinstance(e, int) and e > 0 for e in [0 ,0, 0])
False # Returns False because not a single condition is True.

实际上,任何函数的概念都来自Lisp,或者您可以从函数编程方法中说出来。还有另外一个功能,就是与之相对的所有

>>> all(isinstance(e, int) and e > 0 for e in [1, 33, 22])
True # Returns True when all the condition satisfies.

>>> all(isinstance(e, int) and e > 0 for e in [1, 0, 1])
False # Returns False when a single condition fails.

正确使用这两个功能确实很酷。


11

您应该使用“生成器表达式”-也就是说,一种语言构造可以使用迭代器,然后在一行上应用过滤器和表达式:

例如(i ** 2 for i in xrange(10)),生成前10个自然数(0到9)的平方的生成器

它们还允许“ if”子句过滤“ for”子句上的itens,因此对于您的示例,您可以使用:

any (e for e in [1, 2, 'joe'] if isinstance(e, int) and e > 0)

感谢您调出生成器,因为我认为这是使它最像lambda版本的原因(如果之前的项为false,则不必处理整个列表)。另外,很高兴知道如果它是唯一的参数,我们可以忽略发电机的参数。莫名其妙地错过了..
ShawnFumo

7

对Antoine P答案的改进

>>> any(type(e) is int for e in [1,2,'joe'])
True

对于 all()

>>> all(type(e) is int for e in [1,2,'joe'])
False

6

尽管其他人给出了很好的Python答案(在大多数情况下,我只会使用公认的答案),但我只是想指出,使自己的实用程序函数自己真正喜欢这样做是多么容易:

def any_lambda(iterable, function):
  return any(function(i) for i in iterable)

In [1]: any_lambda([1, 2, 'joe'], lambda e: isinstance(e, int) and e > 0
Out[1]: True
In [2]: any_lambda([-1, '2', 'joe'], lambda e: isinstance(e, int) and e > 0)
Out[2]: False

我认为我至少要先使用function参数定义它,因为它与map()和filter()等现有的内置函数更加匹配:

def any_lambda(function, iterable):
  return any(function(i) for i in iterable)

4

过滤器可以工作,加上它返回匹配的元素

>>> filter(lambda e: isinstance(e, int) and e > 0, [1,2,'joe'])
[1, 2]

2
尽管这是可行的(因为一个空列表为False),但与使用any相比,它有几个缺点。首先,它将遍历整个列表(即使第一个元素为False),并将True项复制到新列表中,从而增加了时间和内存。最后,如果您要做的只是检查是否有任何项目与某项匹配,这会使您的意图不那么清楚。如果您只需要在此之后立即使用匹配项,我同意它可能会很有用(根据您使用结果的方式考虑itertools.ifilter)。
ShawnFumo

4

您可以使用组合anymap,如果你真的想保持你的拉姆达符号,像这样:

any(map(lambda e: isinstance(e, int) and e > 0, [1, 2, 'joe']))

但是最好使用生成器表达式,因为它不会两次构建整个列表。


2

如果您真的想在any()中内联lambda,则可以执行以下操作:

>>> any((lambda: isinstance(e, int))() for e in [1,2,'joe'])
True
>>> any((lambda: isinstance(e, int))() for e in ['joe'])
False

您只需要包装未命名的lambda,并通过添加 ()

这样做的好处是,当您遇到第一个int时,您仍然可以利用短路任何求值的优势

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.