Reputation: 5402
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?
Upvotes: 3
Views: 122
Reputation: 239473
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')
Upvotes: 5