Я пытаюсь найти аккуратный способ суммирования списка и списка списков в одной и той же функции, пока у меня есть:
import operator
"""
Fails late for item = ['a', 'b']
"""
def validate(item):
try:
return sum(item) == sum(range(1, 10))
except TypeError:
return sum(reduce(operator.add, item)) == sum(range(1, 10))
"""
Not valid for item = [1,2,[3,4,5]]
"""
def validate2(item):
if isinstance(item[0], int):
return sum(item) == sum(range(1, 10))
else:
return sum(reduce(operator.add, item)) == sum(range(1, 10))
print validate([1, 2, 3, 4, 5, 6, 7, 8, 9])
print validate([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print validate2([1, 2, 3, 4, 5, 6, 7, 8, 9])
print validate2([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
... но ни один из них не кажется мне совершенно правильным (причины в строках документа). Я хочу знать, есть ли лучший способ суммирования списков и списков списков, которые не требуют, чтобы я обнаруживал исключения или фактически анализировал список до того, как функция решит, что делать.
Очевидно, я все еще ожидаю, что ['a', 'b']
будет недействительным.
Не забудьте точно описать, что вы пытаетесь сделать. Я предполагаю, что вы хотите суммировать все значения до одного значения, а не получать, например. [[1,2], [3,4]] → [3,7]. Здесь простая рекурсия; пять строк кода, если вы пропустите тесты:
def sums(it):
"""
>>> sums(1)
1
>>> sums([1,2,3])
6
>>> sums([1,2,3,[4,5]])
15
>>> sums(['a','b'])
Traceback (most recent call last):
...
TypeError: unsupported operand type(s) for +: 'int' and 'str'
"""
if getattr(it, "__iter__", None):
return sum(map(sums, it))
else:
return it
if __name__ == "__main__":
import doctest
doctest.testmod()
Возможно, вам будет проще сначала сгладить список?
def flatten(xs):
for x in xs:
try:
sub = iter(x)
except TypeError:
yield x
else:
for y in flatten(sub):
yield y
С вышесказанным вы можете сделать это:
In [4]: fs = flatten([1,2,[3,4,[5,6],7],8,[9,10]])
In [5]: list(fs)
Out[5]: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
for x in xs
внутри else:
(и изменить, чтобы yield xs
в исключении), чтобы это работало даже на скалярах. Мне всегда нравится ставить условия рекурсии на входе в функцию.
else:
станет for x in xs: for y in flatten(x): yield y
приведет for x in xs: for y in flatten(x): yield y
. Спасибо за комментарий!
Внешний numpy модуль имеет много операций (включая sum()), которые работают аналогично по скалярам, векторам, матрицам и даже более крупным массивам...
Обратите внимание, что это не работает в смешанных списках, таких как [1,2,[3,4,5]]
, только квадратные матрицы! Так что это точно не отвечает на ваш вопрос.