简体   繁体   中英

Adding tuples to produce a tuple with a subtotal per 'column'

What is the most pythonic way of adding the values of two or more tuples to produce a total for each 'column'?

Eg:

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

I've so far considered the following:

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

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

I'm sure this far from ideal - how can it be improved?

I guess you could use reduce , though it's debatable whether that's pythonic ..

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

Here's another way using map and zip :

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

or, if you're passing your collection of tuples in as a list:

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

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

and, using a list comprehension instead of map :

In [16]: [sum(z) for z in zip(*tups)]
Out[16]: [51, 73]

Since we're going crazy,

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

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

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

Truth is, almost every time I post one of these crazy solutions, the 'naive' method seems to work out faster and more readable...

Not pure Python, but the preferred way if you have SciPy installed:

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

print tuple(a+b+c)

If your set of tuples is going to be relatively small, your solution is fine. However, if you're going to be working on very large data sets you should consider using reduce as it will only iterate over the list once compared to your original solution which iterates over the list of tuples twice.

>>> 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)

These solutions all suffer from one of two problems:

  • they only work on exactly two columns; ((1,2,3),(2,3,4),(3,4,5)) doesn't work; or
  • they don't work on an iterator, so generating a billion rows doesn't work (or wastes tons of memory).

Don't get caught up in the "pythonic" buzzword at the expense of not getting a correct answer.

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)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM