Добавление кортежей для создания кортежа с промежуточной суммой для каждого столбца - PullRequest
2 голосов
/ 15 июля 2009

Какой самый питонический способ сложения значений двух или более кортежей для получения итоговой суммы для каждого «столбца»?

Например:

>>> a = (10, 20)
>>> b = (40, 50)
>>> c = (1, 3)
>>> ???
(51, 73)

До сих пор я считал следующее:

def sumtuples(*tuples):
    return (sum(v1 for v1,_ in tuples), sum(v2 for _,v2 in tuples))

>>> print sumtuples(a, b, c)
(51, 73)

Я уверен, что это далеко от идеала - как это можно улучшить?

Ответы [ 5 ]

7 голосов
/ 15 июля 2009

Я думаю, вы могли бы использовать reduce, хотя это спорно, что будь вещий ..

In [13]: reduce(lambda s, t: (s[0]+t[0], s[1]+t[1]), [a, b, c], (0, 0))
Out[13]: (51, 73)

Вот еще один способ использования map и zip:

In [14]: map(sum, zip(a, b, c))
Out[14]: [51, 73]

или, если вы передаете свою коллекцию кортежей в виде списка:

In [15]: tups = [a, b, c]

In [15]: map(sum, zip(*tups))
Out[15]: [51, 73]

и, используя понимание списка вместо map:

In [16]: [sum(z) for z in zip(*tups)]
Out[16]: [51, 73]
2 голосов
/ 15 июля 2009

Так как мы сходим с ума,

a = (10, 20)
b = (40, 50)
c = (1, 3)

def sumtuples(*tuples):
   return map(sum, zip(*tuples))

sumtuples(a,b,c)
[51, 73]

По правде говоря, почти каждый раз, когда я публикую одно из этих сумасшедших решений, кажется, что «наивный» метод работает быстрее и более читабелен ...

1 голос
/ 15 июля 2009

Не чистый Python, но предпочтительный способ, если у вас установлен SciPy:

from scipy import array
a = array((10, 20))
b = array((40, 50))
c = array((1, 3))

print tuple(a+b+c)
0 голосов
/ 16 июля 2009

Все эти решения страдают одной из двух проблем:

  • они работают только на двух столбцах; ((1,2,3), (2,3,4), (3,4,5)) не работает; или
  • они не работают на итераторе, поэтому генерация миллиарда строк не работает (или тратит тонны памяти).

Не увлекайтесь "питоническим" модным словом за счет неправильного ответа.

def sum_columns(it):
    result = []
    for row in it:
        if len(result) <= len(row):
            extend_by = len(row) - len(result)
            result.extend([0] * extend_by)

        for idx, val in enumerate(row):
            result[idx] += val

    return result

a = (1, 20)
b = (4, 50)
c = (0, 30, 3)
print sum_columns([a,b,c])

def generate_rows():
    for i in range(1000):
        yield (i, 1, 2)

lst = generate_rows()
print sum_columns(lst)
0 голосов
/ 15 июля 2009

Если ваш набор кортежей будет относительно небольшим, ваше решение подойдет. Однако, если вы собираетесь работать с очень большими наборами данных, вам следует подумать об использовании Reduce, поскольку он будет перебирать список только один раз по сравнению с исходным решением, которое перебирает список кортежей дважды.

>>> a = (10, 20)
>>> b = (40, 50)
>>> c = (1, 3)
>>> values=[a,b,c]
>>> reduce(lambda x,y: (x[0]+y[0],x[1]+y[1]), values,(0,0))
(51, 73)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...