Henry Henrinson
Henry Henrinson

Reputation: 5402

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?

Upvotes: 3

Views: 122

Answers (1)

thefourtheye
thefourtheye

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

Related Questions