What you need is a map
and reduce
:
>>> from functools import reduce
>>> yourlist = [2, 3]
>>> reduce(lambda x, y: x*y, map(lambda x: (1-1/x), yourlist))
0.33333333333333337
>>> yourlist = [2, 3, 5]
>>> reduce(lambda x, y: x*y, map(lambda x: (1-1/x), yourlist))
0.2666666666666667
Because map converts each item to the (1-1/item)
and then the reduce
multiplies all of them.
Additional remarks:
Instead of the lambda x, y: x * y
you could also use the faster operator.mul
, for example:
>>> import operator
>>> yourlist = [2, 3, 5]
>>> reduce(operator.mul, map(lambda x: (1-1/x), yourlist))
0.2666666666666667
Thanks @acushner for pointing this out (in the comments).
What went wrong in your function
In this case it's actually quite easy to see what doesn't work, just use a named function and add some print
s:
def myfunc(x, y):
print('x = {}'.format(x))
print('y = {}'.format(y))
res = (1 - 1.0/x) * (1 - 1.0/y)
print('res = {}'.format(res))
return res
reduce(myfunc, [2, 3])
# x = 2
# y = 3
# res = 0.33333333333333337
reduce(myfunc, [2, 3, 5])
# x = 2
# y = 3
# res = 0.33333333333333337
# x = 0.33333333333333337
# y = 5
# res = -1.5999999999999996
So it uses the last result as "next" x
value. That's why it worked for the length-2-list case but for more elements it simply doesn't apply the formula you want.
Alternative
Instead of using map
and reduce
you could also use a simple for
-loop. It's much easier to get them right and most of the times they are more readable (and in some cases it's faster than reduce
).
prod = 1
for item in yourlist:
prod *= 1 - 1 / item
print(prod)
Yes, instead of 1 line it's now 4 lines long but it's easy to understand what is happening (but there might be some edge cases in which that doesn't behave like reduce
, for example for empty inputs).
But I generally prefer simple loops over complicated reduce
-operations but as always YMMV. :)