35

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?

8 Answers 8

71
[sum(a) for a in zip(*array)]
Sign up to request clarification or add additional context in comments.

Comments

63

[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]

Comments

14

An alternative way:

map(sum, zip(*array))

Comments

8

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.

Comments

3

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.

Comments

2

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.

Comments

0

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

2 Comments

Hm, while interesting, that's not really an answer to this question (and may thus attract downvotes). You could, for example, ask the question "How can I interleave several lists?" and answer it yourself. Maybe use an example that uses more than two lists, otherwise someone will suggest ",".join(a).
Agreed Tim. It is apropros of this 'q&a' being pointed to by a thread that deals interleaving lists, but marked as a duplicate of this question! I used ',' in the example, just for simplicity, my code required actual lists of user defined classes to be interleaved, but that would be hard to excuse in the abstract.
0

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, ...

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.