Reduce(X + Y, XS) и сумма (XS) не эквивалентны в Python?

Однако я ожидаю, что эти два значения будут означать одно и то же с функциональной точки зрения:

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

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

sum(zip(x, y))  # fails

Почему sum терпеть неудачу здесь?

1 ответ

Решение

Актуальная проблема в том, что с sumНачальное значение по умолчанию. Цитирование документации,

Суммы начинаются и элементы итерируются слева направо и возвращаются итоги. начать по умолчанию0, Элементы итерируемого элемента обычно являются числами, и начальное значение не может быть строкой.

Но, в случае reduceЕсли не указано необязательное начальное значение, оно будет использовать первое значение в итерируемом качестве инициализатора. Так, reduce на самом деле оценивает это так

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

поскольку sum принимает начальное значение равным 0, он оценивает его следующим образом:

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

В этом случае он пытается добавить 0 с кортежем, и именно поэтому вы получаете

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

Чтобы это исправить, передайте пустой кортеж, чтобы sumначнем, вот так

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

Теперь, когда начальное значение является пустым кортежем, оценка происходит следующим образом

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

Примечание. В обоих случаях будет создано более одного промежуточного кортежа. Чтобы избежать этого, я бы порекомендовал сгладить данные и передать их tuple конструктор как выражение генератора, как это

>>> tuple(item for items in zip(x, y) for item in items)
(1, 'a', 2, 'b', 3, 'c')
Другие вопросы по тегам