两个列表的逐元素相加?

339

我现在拥有:

list1 = [1, 2, 3]
list2 = [4, 5, 6]

我希望有:

[1, 2, 3]
 +  +  +
[4, 5, 6]
|| || ||
[5, 7, 9]

这是两个列表逐元素相加的简单操作。

我可以遍历这两个列表,但我不想这样做。

什么是最符合Python风格的实现方式?


可能是Python中简洁的向量加法?的重复问题。 - Nikos Alexandris
17个回答

471
使用mapoperator.add
>>> from operator import add
>>> list( map(add, list1, list2) )
[5, 7, 9]

或使用列表推导式与zip

>>> [sum(x) for x in zip(list1, list2)]
[5, 7, 9]

时间比较:

>>> list2 = [4, 5, 6]*10**5
>>> list1 = [1, 2, 3]*10**5
>>> %timeit from operator import add;map(add, list1, list2)
10 loops, best of 3: 44.6 ms per loop
>>> %timeit from itertools import izip; [a + b for a, b in izip(list1, list2)]
10 loops, best of 3: 71 ms per loop
>>> %timeit [a + b for a, b in zip(list1, list2)]
10 loops, best of 3: 112 ms per loop
>>> %timeit from itertools import izip;[sum(x) for x in izip(list1, list2)]
1 loops, best of 3: 139 ms per loop
>>> %timeit [sum(x) for x in zip(list1, list2)]
1 loops, best of 3: 177 ms per loop

17
如果你使用那些巨大的数组,@BasSwinckels 的NumPy解决方案可能是你应该考虑的。 - Henry Gomersall
1
你在这些时间测试中使用了哪个Python版本? - arshajii
11
注意:在Python3中,map()函数返回的是一个可迭代对象而不是列表。如果你需要一个实际的列表,可以使用第一种方法:list(map(add, list1, list2))。 - FLHerne
随着@FLHerne指出的map问题在Python3中的注意,这个问题将会变得越来越重要。Python 2将在不到3年的时间内失去官方支持。 - nealmcb
1
有很多时候,Python语法非常优雅简洁,但不幸的是,这并不是其中之一。对于这样一个简单的任务来说,真是太可惜了......为什么他们要让“+”连接列表,而已经有了.extend()方法呢? - Nic Scozzaro
显示剩余4条评论

132

其他人给出了如何在纯Python中实现此操作的示例。如果要处理包含10万个元素的数组,建议使用numpy:

In [1]: import numpy as np
In [2]: vector1 = np.array([1, 2, 3])
In [3]: vector2 = np.array([4, 5, 6])

对每个元素进行加法操作现在变得非常简单,只需

In [4]: sum_vector = vector1 + vector2
In [5]: print sum_vector
[5 7 9]

就像在Matlab中一样。

与Ashwini最快版本进行比较的时间:

In [16]: from operator import add
In [17]: n = 10**5
In [18]: vector2 = np.tile([4,5,6], n)
In [19]: vector1 = np.tile([1,2,3], n)
In [20]: list1 = [1,2,3]*n
In [21]: list2 = [4,5,6]*n
In [22]: timeit map(add, list1, list2)
10 loops, best of 3: 26.9 ms per loop

In [23]: timeit vector1 + vector2
1000 loops, best of 3: 1.06 ms per loop

这样会快25倍!但使用适合您情况的工具。对于简单程序,您可能不想安装numpy,因此请使用标准python(我发现Henry的版本最符合Pythonic风格)。如果您需要进行大量数值计算,请让numpy来做重活。对于速度狂热者:似乎numpy方案在n = 8左右开始更快。


80
[a + b for a, b in zip(list1, list2)]

6
接受的回答更快,而且它包含了这个答案(更具信息性)。 - Sibbs Gambling
4
虽然我理解你的观点(并且完全不反感),但我认为值得指出的是,我总是会使用我提出的解决方案(因为它不需要导入任何内容,因此可以说是最简单的解决方案,同时也可以说是更符合Python风格的),或者在速度很重要的情况下,使用 Bas Swinckel 的答案,后者在速度至关重要时是绝对正确的选择。 - Henry Gomersall
是的。谢谢您的意见。但本质上[sum(x) for x in zip(list1, list2)]与您的答案相同,不是吗? :) - Sibbs Gambling
5
大致上来说(虽然是编辑后添加的)我个人更喜欢使用 a+b 表示法,并显式地进行元组解包以达到更好的可读性和 Python 风格。 - Henry Gomersall

16

如他人所述,一种快速且占用空间较少的解决方案是使用Numpy(np)及其内置的向量操作能力:

1. 使用Numpy

x = np.array([1,2,3])
y = np.array([2,3,4])
print x+y

2. 通过内置函数实现

2.1 Lambda表达式

list1=[1, 2, 3]
list2=[4, 5, 6]
print map(lambda x,y:x+y, list1, list2)

注意,map()支持多个参数。

2.2 zip和列表推导式

list1=[1, 2, 3]
list2=[4, 5, 6]
print [x + y for x, y in zip(list1, list2)]

1
对 Lambda 方法点赞。可惜这个解决方案与其他解决方案合并,而这些解决方案在别处已经重复了。 - LondonRob

15

在我看来,使用numpy更简单:

import numpy as np
list1=[1,2,3]
list2=[4,5,6]
np.add(list1,list2)

结果:

Terminal execution

有关详细参数信息,请查看此处:numpy.add


9
也许这是Pythonic的,如果你有数量未知的列表而且不需要导入任何东西,它会有点用处。
只要列表长度相同,您可以使用下面的函数。
这里的*args接受可变数量的列表参数(但仅求和每个列表中相同数量的元素)。
然后,在返回的列表中再次使用*来解包每个列表中的元素。
def sum_lists(*args):
    return list(map(sum, zip(*args)))

a = [1,2,3]
b = [1,2,3]  

sum_lists(a,b)

输出:

[2, 4, 6]

或者使用3个列表

sum_lists([5,5,5,5,5], [10,10,10,10,10], [4,4,4,4,4])

输出:

[19, 19, 19, 19, 19]

8

也许“最Pythonic的方式”应该包括处理list1和list2大小不同的情况。使用其中一些方法可能会悄悄地给你一个答案。使用numpy方法则可能会提示一个ValueError。

示例:

import numpy as np
>>> list1 = [ 1, 2 ]
>>> list2 = [ 1, 2, 3]
>>> list3 = [ 1 ]
>>> [a + b for a, b in zip(list1, list2)]
[2, 4]
>>> [a + b for a, b in zip(list1, list3)]
[2]
>>> a = np.array (list1)
>>> b = np.array (list2)
>>> a+b
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: operands could not be broadcast together with shapes (2) (3)

如果这个函数在你的问题中使用,你希望得到哪个结果?

在这种情况下,人们应该绝对考虑使用itertools中的zip_longest函数,并将fillvalue设置为0 - Ma0

7
这很简单,使用numpy.add()即可。
import numpy

list1 = numpy.array([1, 2, 3])
list2 = numpy.array([4, 5, 6])
result = numpy.add(list1, list2) # result receive element-wise addition of list1 and list2
print(result)
array([5, 7, 9])

查看文档

如果您想接收一个 Python 列表:

result.tolist()

6
这将适用于两个或更多的列表;通过迭代列表的列表,但使用numpy加法来处理每个列表的元素。
import numpy as np
list1=[1, 2, 3]
list2=[4, 5, 6]

lists = [list1, list2]
list_sum = np.zeros(len(list1))
for i in lists:
   list_sum += i
list_sum = list_sum.tolist()    

[5.0, 7.0, 9.0]

6

如果你需要处理不同大小的列表,不用担心!神奇的itertools模块可以帮助你:

>>> from itertools import zip_longest
>>> list1 = [1,2,1]
>>> list2 = [2,1,2,3]
>>> [sum(x) for x in zip_longest(list1, list2, fillvalue=0)]
[3, 3, 3, 3]
>>>

在Python 2中,zip_longest被称为izip_longest
另请参见这个相关问题的答案和评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接