Merging/adding lists in Python

Question:

I’m pretty sure there should be a more Pythonic way of doing this – but I can’t think of one: How can I merge a two-dimensional list into a one-dimensional list? Sort of like zip/map but with more than two iterators.

Example – I have the following list:

array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

I want to have

result = [12, 15, 18] # [1+4+7, 2+5+8, 3+6+9]

So far what I’ve come up with is:

def add_list(array):
    number_items = len(array[0])
    result = [0] * number_items
    for index in range(number_items):
        for line in array:
            result[index] += line[index]
    return result

But that doesn’t look very elegant/Pythonic to me. Aside from not checking if all the “lines” in the 2D array are of the same length, can be added to each other, etc. What would be a better way to do it?

Asked By: Tim Pietzcker

||

Answers:

[sum(a) for a in zip(*array)]
Answered By: Ned Batchelder

[sum(value) for value in zip(*array)] is pretty standard.

This might help you understand it:

In [1]: array=[[1, 2, 3], [4, 5, 6], [7, 8, 9]]

In [2]: array
Out[2]: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

In [3]: *array
------------------------------------------------------------
   File "<ipython console>", line 1
     *array
     ^
<type 'exceptions.SyntaxError'>: invalid syntax

The unary star is not an operator by itself. It unwraps array elements into arguments into function calls.

In [4]: zip(*array)
Out[4]: [(1, 4, 7), (2, 5, 8), (3, 6, 9)]

zip() is a built-in function

In [5]: zip(*array)[0]
Out[5]: (1, 4, 7)

each element for the list returned by zip is a set of numbers you want.

In [6]: sum(zip(*array)[0])
Out[6]: 12

In [7]: [sum(values) for values in zip(*array)]
Out[7]: [12, 15, 18]
Answered By: Charles Merriam

If you’re doing a lot of this kind of thing, you want to learn about scipy.

>>> import scipy
>>> sum(scipy.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]))
array([12, 15, 18])

All array sizes are checked for you automatically. The sum is done in pure C, so it’s very fast. scipy arrays are also very memory efficient.

The drawback is you’re dependent on a fairly complex third-party module. But that’s a very good tradeoff for many purposes.

Answered By: Alex Coventry

An alternative way:

map(sum, zip(*array))
Answered By: ngn

Agree with fivebells, but you could also use Numpy, which is a smaller (quicker import) and more generic implementation of array-like stuff. (actually, it is a dependency of scipy). These are great tools which, as have been said, are a ‘must use’ if you deal with this kind of manipulations.

Answered By: heltonbiker

Late to the game, and it’s not as good of an answer as some of the others, but I thought it was kind of cute:

map(lambda *x:sum(x),*array)

it’s too bad that sum(1,2,3) doesn’t work. If it did, we could eliminate the silly lambda in there, but I suppose that would make it difficult to discern which (if any) of the elements is the “start” of the sum. You’d have to change that to a keyword only arguement which would break a lot of scripts … Oh well. I guess we’ll just live with lambda.

Answered By: mgilson

[sum(a) for a in zip(*array)]

I like that. I needed something related for interleaving objects in to a list of items, came up with something similar but more concise for even length lists:

sum(zip(*array),())

for example, interleaving two lists:

a = [1,2,3]
b = ['a','b','c']
sum(zip(a,b),())
(1, 'a', 2, 'b', 3, 'c')
Answered By: F1Rumors

You can simply do this:

print [sum(x) for x in zip(*array)]

If you wish to iterate through lists in this fashion, you can use chain of the itertools module:

from itertools import chain

for x in array.chain.from_iterable(zip(*array)):
    print x   
# prints 1, 4, 7, 2, 5, 8, ...
Answered By: Saksham Varma
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.