0

我知道 reduce 和 all/any 可以解决问题,但是当列表很大时,它的性能很差。

例如:

定义一个函数,包括 print 来检查函数是否已经执行

In [33]: def func(x):
   ....:     print x
   ....:     return bool(x)
   ....: 

operator.or_作为reduce函数传递

In [34]: import operator
In [35]: reduce(operator.or_, [func(1), func(0)])
1
0
Out[35]: True

然后我们发现即使第一个函数返回True,第二个函数也已执行。

如果我直接使用or操作,一旦发现其中一个返回True,它会立即返回。

In [36]: func(1) or func(0)
1
Out[36]: True

但是,如果我有一个很大的列表,我就不能这样做。

有什么优雅的方法可以做到这一点吗?或者我应该检查什么 for 循环?

更新

我用于任何的起源方式是

In [26]: any([func(1), func(0)])
1
0
Out[26]: True

它确实评估了所有功能。

通过@Martijn Pieters 的回答,我现在知道我可能会以错误的方式使用它。很抱歉不清楚。

4

2 回答 2

4

any()正是您这里需要的,并结合了生成器表达式:

any(func(i) for i in big_list)

这将停止迭代func(i)返回真值的第一个值。一旦True找到一个值,您就证明了输入序列中存在一个为真的值(“是否有任何为真的值?”-> 是的,我们至少找到了一个)。

对于and,您可以all()改用:

all(func(i) for i in big_list)

这将在找到虚假值False的那一刻返回。func(i)如果找到一个错误值,那么您已经证明至少有一个值不正确,因此它们不可能都是正确的。

请注意,这两个函数都有一个生成器表达式:

(func(i) for i in big_list)

这是懒惰地评估的;每次您请求生成器表达式的下一个值时,它都会评估循环并执行func(i)一次表达式。它不会一次生成整个列表,它会一个接一个地生成项目。

您的reduce(operator.or_, [func(1), func(0)])表达式必须先构建整个输入列表,然后才能调用reduce(). 该reduce()方法将处理整个输入列表,它不会短路,因为它不知道对输入值应用了什么操作。你也可以给出一个生成器表达式,但是一旦设置了结果(在第一个真值上或第一个假值上)reduce()它就不会停止迭代,这也是因为对正在执行的操作没有专业知识。orandreduce()

于 2013-11-06T17:41:23.023 回答
1

添加到另一个答案,这个问题:

reduce(operator.or_, [func(1), func(0)])

是不是总是在调用函数之前对参数进行评估,因为 Python 不进行惰性评估。使用迭代器(如在 Martijn 的回答中)可以避免这种情况,因为它会根据需要生成列表,而不是一次生成所有列表。

于 2013-11-06T17:43:16.247 回答