Reputation: 31
>>> import functools
>>> functools.reduce(lambda acc, val: acc + 1 if val == ' ' else 0, list("test test test"), 0)
0
I just want to count whitespaces in the text so I expected the function to return 2
(because there are two whitespaces) not 0
.
Upvotes: 1
Views: 296
Reputation: 152775
An easy way to debug lambda
s is to use a print() or (original lambda content)
. That works because print
always returns None
and therefore Python will always execute the part after the or
.
Applying that to your case:
import functools
functools.reduce(lambda acc, val: print(acc, val) or (acc + 1 if val == ' ' else 0), list("test test test"), 0)
which prints:
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
This gives an explanation what went wrong: You don't keep the acc
umulator in case it's not a whitespace.
There are several ways to fix this. I'll keep the print
for debugging reasons but if you really want to use any of those you probably should remove it.
One would be to use the fact that booleans behave like integers if used in arithmetic operations:
functools.reduce(lambda acc, val: print(acc, val) or (acc + (val == ' ')), list("test test test"), 0)
This adds 1 (True
) to the accumulator whenever it encounters a whitespace otherwise it adds 0 (False
).
Or the trivial solution to just keep the acc
:
functools.reduce(lambda acc, val: print(acc, val) or (acc + 1 if val == ' ' else acc), list("test test test"), 0)
But there are much better ways to count whitespaces than using reduce
and lambda
. For example:
"test test test".count(" ")
which also works for your list:
list("test test test").count(" ") # but that's slower
or:
from collections import Counter
cnts = Counter("test test test") # counts all letters
cnts[" "]
Upvotes: 1
Reputation: 34290
The expression:
acc + 1 if val == ' ' else 0
is parsed as
(acc + 1) if val == ' ' else 0
so, the accumulator is reset every time it encounters anything but space. So it should be either:
acc + 1 if val == ' ' else acc
or
acc + (1 if val == ' ' else 0)
or even just:
acc + (val == ' ')
But, of course, str.count()
is the way to go there.
Upvotes: 1