简体   繁体   中英

reduce(x+y, xs) and sum(xs) are not equivalent in python?

I would expect the two to mean the same, from a functional equational standpoint, however:

x = [1, 2, 3]
y = ['a', 'b', 'c']

reduce(lambda x, y: x + y, zip(x, y))  # works

sum(zip(x, y))  # fails

Why is sum failing here?

The actual problem is, with the sum 's default start value. Quoting the documentation ,

Sums start and the items of an iterable from left to right and returns the total. start defaults to 0 . The iterable's items are normally numbers, and the start value is not allowed to be a string.

But, in case of reduce , if no optional start value is given, it will use the first value in the iterable as the initializer. So, reduce is actually evaluating it like this

( ( (1, 'a') + (2, 'b') ) + (3, 'c') )

Since sum assumes start value as 0, it evaluates it like this,

0 + (1, 'a') + (2, 'b') + (3, 'c')

In this case, it tries to add 0 with a tuple and that is why you are getting

TypeError: unsupported operand type(s) for +: 'int' and 'tuple'

To fix this, pass an empty tuple, to sum 's start, like this

>>> sum(zip(x, y), tuple())
(1, 'a', 2, 'b', 3, 'c')

Now, with the initial value being an empty tuple, the evaluation happens like this

() + (1, 'a') + (2, 'b') + (3, 'c')

Note: In both these case, there will be more than one intermediate tuples created. To avoid that, I would recommend flattening the data and pass it to tuple constructor as a generator expression, like this

>>> tuple(item for items in zip(x, y) for item in items)
(1, 'a', 2, 'b', 3, 'c')

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM