对Python的reduce函数感到困惑
我在尝试理解Python的reduce这个内置方法是怎么工作的,所以我试了一些简单的例子。但这里有一个例子我不太明白,如果有人能给我一些提示,我会非常感激。
我有一个数组,里面有几个质数,像这样:
>>> arr
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199]
然后我尝试像这样使用reduce函数:
>>> reduce(lambda x, y: is_prime(x) and is_prime(y), arr)
False
我不太明白为什么这里的答案是False而不是True,因为我只是把is_prime的所有结果进行与运算,而数组中的所有数字都是质数,这样is_prime应该对每个数字都返回True。
我还检查了数组中的每个数字实际上都对我的is_prime()返回True:
>>> for n in arr:
... if not is_prime(n):
... print n
...
>>>
我一定是漏掉了什么,有人能帮忙吗?谢谢。
4 个回答
传给reduce()的这个有两个参数的函数,应该返回一个和输入类型相同的值,也就是说,它是把两个值“缩减”成一个值;reduce()会反复应用这个函数,把整个输入的可迭代对象(比如列表)缩减成一个单一的值。
经典的例子是:用 lambda x,y:x+y
来计算输入的总和。
如果你想要的结果是判断列表中的每个数字是否都是质数,可以使用内置的all()函数:
they_are_all_primes=all((is_prime(x) for x in [2,3,5]))
在这个lambda表达式中,第一个参数(x)是累积值,第二个参数(y)是迭代值。试试这个:
reduce(lambda x, y: x and is_prime(y), arr, True)
所以x会被替换为从True开始的累积值(初始的累积值),这样True和is_prime(2)的结果是True,所以True会传递到下一次迭代中……
接下来我们来实验一下,检查所有的数字是否都是奇数:
>>> arr = [3, 5, 7, 11, 15]
>>> reduce(lambda x, y: x and y%2!=0, arr, True)
True
现在我将定义一个函数,用来打印中间的累积值:
>>> def xxx(y):
... print y
... return y
...
>>> reduce(lambda x, y: xxx(x) and y%2!=0, arr, True)
True
True
True
True
True
True
>>> arr = [3, 5, 7, 12, 15]
>>> reduce(lambda x, y: xxx(x) and y%2!=0, arr, True)
True
True
True
True
False
False
>>>
这样命名变量会更清晰:
reduce(lambda accumulated, number: accumulated and is_prime(number), arr, True)
is_prime(x) and is_prime(y)
这段代码的结果会是一个布尔值,也就是说它的结果要么是“真”(True),要么是“假”(False)。在下一次循环中,这个结果会作为参数传给lambda函数的 x
。
所以,如果有任何一次调用 is_prime
返回 False
,那么整个结果就会变成 False
。因为:
第一次循环:
(Default Value & First Value)
从第二次循环开始:
(Previous Result & Current Value)
由于这是一个“与”(and)操作的系列,如果其中任何一个结果是 False
,那么整个表达式的结果就会被评估为 False
。
想想你正在一个一个地处理这些值:
>>> reduce(lambda x,y: isprime(x) and isprime(y), [2])
2
只有一个元素,所以 reduce
直接给我们第一个。
>>> reduce(lambda x,y: isprime(x) and isprime(y), [2, 3])
True
这很合理:两个都是质数。
>>> reduce(lambda x,y: isprime(x) and isprime(y), [2, 3, 5])
False
这个看起来有点奇怪,但其实是因为你实际上在调用
isprime(True) and isprime(5)
因为 True
是最后一个值,而 True
的 int
值是 1:
>>> int(True)
1
reduce
和 all
是不一样的。