为什么我的lambda表达式减少不能按预期工作?

时间:2017-08-16 12:52:03

标签: python lambda reduce counting

>>> import functools
>>> functools.reduce(lambda acc, val: acc + 1 if val == ' ' else 0, list("test test test"), 0)
0

我只想计算文本中的空格,所以我希望函数返回2(因为有两个空格)而不是0

2 个答案:

答案 0 :(得分:1)

表达式:

acc + 1 if val == ' ' else 0

被解析为

(acc + 1) if val == ' ' else 0

所以,每次遇到空间时都会重置累加器。所以应该是:

acc + 1 if val == ' ' else acc

acc + (1 if val == ' ' else 0)

甚至只是:

acc + (val == ' ')

但是,当然,str.count()是去那里的方式。

答案 1 :(得分:1)

调试lambda的简便方法是使用print() or (original lambda content)。这是有效的,因为print总是返回None,因此Python将始终在or之后执行该部分。

将其应用于您的案例:

import functools
functools.reduce(lambda acc, val: print(acc, val) or (acc + 1 if val == ' ' else 0), list("test test test"), 0)

打印:

0 t
0 e
0 s
0 t
0  
1 t
0 e
0 s
0 t
0  
1 t
0 e
0 s
0 t
0

这解释了出现了什么问题:如果不是空格,请不要保留acc umulator。

有几种方法可以解决这个问题。出于调试原因,我会保留print,但如果你真的想使用其中任何一个,你可能应该删除它。

如果在算术运算中使用,则可以使用布尔行为类似于整数的事实:

functools.reduce(lambda acc, val: print(acc, val) or (acc + (val == ' ')), list("test test test"), 0)

每当遇到空格时,它会向累加器添加1(True),否则会增加0(False)。

或者保留acc

的简单解决方案
functools.reduce(lambda acc, val: print(acc, val) or (acc + 1 if val == ' ' else acc), list("test test test"), 0)

但是,使用reducelambda计算空格的方法要好得多。例如:

"test test test".count(" ")

也适用于您的列表:

list("test test test").count(" ")  # but that's slower

或:

from collections import Counter
cnts = Counter("test test test")  # counts all letters
cnts[" "]