Reputation: 336118
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?
Upvotes: 35
Views: 23378
Reputation: 2130
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, ...
Upvotes: 0
Reputation: 948
[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')
Upvotes: 0
Reputation: 309841
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
.
Upvotes: 2
Reputation: 27575
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.
Upvotes: 3
Reputation: 70819
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.
Upvotes: 8
Reputation: 20500
[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]
Upvotes: 63