Суммирование нецелых чисел в Python sum ([[1], [2]]) = [1,2] - PullRequest
3 голосов
/ 23 июля 2010

Можно ли взять в Python сумму нецелых чисел?

Команда

sum([[1],[2]])

например, выдает ошибку

Traceback (most recent call last):
  File "<pyshell#28>", line 1, in <module>
    sum([[1,2,3],[2,3,4]])
TypeError: unsupported operand type(s) for +: 'int' and 'list'

Я подозреваю, что sum пытается добавить 0 в список [1], что приводит к сбою. Я уверен, что есть много способов, чтобы обойти это ограничение (обернуть вещи в классе и реализовать __radd__ вручную), но есть ли более элегантный способ сделать это?

Ответы [ 7 ]

9 голосов
/ 23 июля 2010

Похоже, вы хотите это:

>>> sum([[1],[2]], [])
[1, 2]

Вы правы, что он пытается добавить 0 к [1] ​​и получает ошибку. Решение состоит в том, чтобы дать sum дополнительный параметр, дающий начальное значение, которое для вас будет пустым списком.

Редактировать: Однако, как говорит Гнибблер, sum не является хорошим способом объединения вещей. И если вы просто хотите объединить последовательность вещей, вам, вероятно, следует использовать reduce, а не создавать собственную __radd__ функцию только для использования sum. Вот пример (с таким же плохим поведением, как у sum):

>>> reduce(lambda x, y: x+y, [[1],[2]])
[1, 2]
8 голосов
/ 23 июля 2010

Плохо использовать sum() для чего-либо, кроме чисел, так как он имеет квадратичную производительность для последовательностей / строк / и т.д.

Лучше использовать понимание списка для суммирования ваших списков

[j for i in [[1],[2]] for j in i]
5 голосов
/ 23 июля 2010

Более эффективно объединять, используя itertools.chain.

>>> m = [[i] for i in range(200)]
>>> m
[[0], [1], [2], [3], [4], [5], [6], [7], [8], ...]
>>> from itertools import *
>>> list(chain(*m))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, ...]

Лично я предпочитаю это пониманию списка, так как трудно вспомнить, какой цикл for стоит первым. Есть даже более эффективный вариант, list(chain.from_iterable(m)).

Результаты микробенчмарка (в Python 3 используется модуль timeit. Размер списка p x q означает m = [list(range(q)) for _ in range(p)]):

list size | chain(*m)  | sum(m,[])     | list comp  | flatten    |
----------+------------+---------------+------------+------------+
    2 x 1 |   1.78 µs  |      0.646 µs |   0.905 µs |    1.49 µs |
   20 x 1 |   4.37 µs  |      7.49  µs |   5.19  µs |    3.59 µs |
  200 x 1 |  26.9  µs  |    134     µs |  40     µs |   24.4  µs |
 2000 x 1 | 233    µs  | 12.2       ms | 360     µs | 203     µs |
----------+------------+---------------+------------+------------+
 2 x    1 |   1.78 µs  |      0.646 µs |   0.905 µs |    1.49 µs |
 2 x   10 |   2.55 µs  |      0.899 µs |   3.14  µs |    2.2  µs |
 2 x  100 |   9.07 µs  |      2.03  µs |  17.2   µs |    8.55 µs |
 2 x 1000 |  51.3  µs  |     21.9   µs | 139     µs |   49.5  µs |
----------+------------+---------------+------------+------------+

chain(*m) -> list(chain(*m))
sum(m,[]) -> sum(m, [])
list comp -> [j for i in m for j in i]
flatten   -> icfi = chain.from_iterable; list(icfi(m))

Это показывает, что sum эффективен только , когда размер внешнего списка очень короткий . Но тогда у вас есть еще более эффективный вариант: m[0]+m[1].

3 голосов
/ 23 июля 2010

Как документы говорят,

Итерируемые элементы обычно номера, и не допускается строки.

Это означает, что утомительный процесс фактического запрещения чего-либо, кроме чисел (за исключением запрета суммирования, особенно отвратительной и распространенной ошибки) был отменен - ​​если вы что-то суммируете , но чисел, вы, вероятно, разрушите производительность своей программы без всякой хорошей цели, но, эй, Python на самом деле не ставит цель помешать программистам совершать каждую своего рода ужасную ошибку.

Если вы настаиваете на том, чтобы поступать неправильно, как уже упоминалось в других ответах, использование третьего параметра sum (в качестве начального значения вместо значения по умолчанию 0) является правильным способом сделать не то ;-). Итак, буквальный ответ на ваш вопрос:

Можно ли взять сумму не целые числа в питоне?

(как только удаляется очень ошибочное предположение, что целые числа ведут себя иначе, чем любые другие виды чисел здесь, перефразируя его как «не числа» - суммирование любых видов чисел вполне нормально , и не обязательно требует каких-либо особых мер предосторожности, хотя math.fsum лучше для суммирования float s) ...: "Да, возможно возможно (так же, как это можно использовать молоток, чтобы больно ударить по большому пальцу) - учтите, это совершенно не желательно (точно так же, как не бить по большому пальцу), но это определенно возможно , если вы действительно настаиваете "; -).

1 голос
/ 23 июля 2010

Я немного неправильно понял ваш вопрос для дополнения и сделал следующее решение:

# for me the guestion looks for me to do sum of sum of list
# i would do like this
list_of_numlists=[[1,2,3],[2,3,4]]
print "Input =",list_of_numlists
sum_of_it=sum(sum(x) for x in list_of_numlists)
print "Sum = %i" % sum_of_it
## --> Sum = 15
# second version to understand the request is
sum_of_items=[sum(x) for x in zip(*list_of_numlists)]
print "Sum of each is", sum_of_items
""" Output:
Input = [[1, 2, 3], [2, 3, 4]]
Sum = 15
Sum of each is [3, 5, 7]
"

""

На самом деле вы должны говорить не о сумме, а о последовательности или объединении последовательностей.

0 голосов
/ 23 июля 2010

Для последовательностей из одного элемента также существует специальное решение:

m = [[i] for i in range(200)]
list_of_m = list((zip(*m))[0])
print list_of_m

Также, если в списке есть строки, вы можете использовать стандартное соединение Python для объединения

''.join(m)
0 голосов
/ 23 июля 2010

сумма (повторяемая [, начало]) Суммы начинаются и элементы итерируются слева направо и возвращают итоги. start по умолчанию равно 0. Итерируемые элементы обычно являются числами и не могут быть строками. В [26]: сумма ([[1], [2]], []) Out [26]: [1, 2]

Как в Документах ...

Кстати, Гейб дал правильное решение использовать редуктор (лямбда х, у: х + у, [[1], [2]]). В качестве альтернативы вы можете использовать метод непрофессионала: -

В [69]: l = [[1], [2]]

В [70]: a = str (l [0]). Strip ('[]')

В [71]: b = str (l [1]). Strip ('[]')

В [72]: l = [int (a), int (b)]

В [73]: л Выход [73]: [1, 2]

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...