Yếu tố bổ sung khôn ngoan của 2 danh sách?


244

Tôi có ngay bây giờ:

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

Tôi muốn có:

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

Đơn giản chỉ là một yếu tố bổ sung khôn ngoan của hai danh sách.

Tôi chắc chắn có thể lặp lại hai danh sách, nhưng tôi không muốn làm điều đó.

Là những gì các Pythonic cách mà hầu hết làm như vậy?


Câu trả lời:


364

Sử dụng mapvới operator.add:

>>> from operator import add
>>> list( map(add, list1, list2) )
[5, 7, 9]

hoặc zipvới một sự hiểu biết danh sách:

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

So sánh thời gian:

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

10
Nếu bạn sử dụng các mảng lớn đó, giải pháp gọn gàng của @BasSwinckels có lẽ là thứ bạn nên xem xét.
Henry Gomersall

1
Phiên bản Python nào bạn đã sử dụng cho những thời gian đó?
arshajii

9
NB - trong python3, map () trả về một thứ lặp đi lặp lại thay vì một danh sách. Nếu bạn cần một danh sách thực tế, câu trả lời đầu tiên là danh sách (bản đồ (thêm, list1, list2))
FLHerne

Lưu ý vấn đề python3 được ghi nhận bởi @FLHerne với mapsẽ ngày càng quan trọng hơn theo thời gian. Python 2 sẽ mất hỗ trợ chính thức trong vòng chưa đầy 3 năm.
nealmcb

1
Có nhiều lần cú pháp python thực sự thanh lịch và đơn giản, nhưng thật không may, đây không phải là một trong số đó. Và đối với một nhiệm vụ đơn giản như vậy, thật đáng tiếc .... Tại sao họ lại tạo "+" ghép các danh sách khi đã có phương thức .extend ()?
Nic Scozzaro

105

Những người khác đã đưa ra ví dụ làm thế nào để làm điều này trong python thuần. Nếu bạn muốn làm điều này với các mảng có 100.000 phần tử, bạn nên sử dụng numpy:

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

Thực hiện bổ sung phần tử khôn ngoan bây giờ cũng tầm thường như

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

giống như trong Matlab.

Thời gian để so sánh với phiên bản nhanh nhất của 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

Vì vậy, đây là một yếu tố 25 nhanh hơn! Nhưng sử dụng những gì phù hợp với tình hình của bạn. Đối với một chương trình đơn giản, có lẽ bạn không muốn cài đặt numpy, vì vậy hãy sử dụng python tiêu chuẩn (và tôi thấy phiên bản của Henry là phiên bản Pythonic nhất). Nếu bạn đang rơi vào tình trạng khủng hoảng số nghiêm trọng, hãy numpythực hiện việc nâng vật nặng. Đối với những kẻ cuồng tốc độ: có vẻ như giải pháp numpy bắt đầu nhanh hơn xung quanh n = 8.


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

4
@deltab Câu trả lời được chấp nhận nhanh hơn VÀ nó chứa câu trả lời này (nhiều thông tin hơn)
Đánh bạc Sibbs

2
@ perfectionm1ng mặc dù tôi hiểu quan điểm của bạn (và đừng bắt bẻ nó một chút) Tôi chỉ nghĩ rằng nó đáng để chỉ ra rằng tôi sẽ luôn sử dụng giải pháp mà tôi đã trình bày như được cho là càng nhiều pythonic), hoặc khi tốc độ được tính, câu trả lời của Bas Swinckel , đây là lựa chọn hoàn toàn đúng đắn khi tốc độ quan trọng.
Henry Gomersall

Đúng. Cảm ơn ý kiến. Nhưng về cơ bản [sum(x) for x in zip(list1, list2)]là giống như câu trả lời của bạn, phải không? :)
Đánh bạc Sibbs

4
@ perfectionm1ng Nhiều hơn hoặc ít hơn (mặc dù nó đã được thêm vào sau khi tôi chỉnh sửa :). Cá nhân, tôi thích ký hiệu a + b hơn với việc giải nén tuple rõ ràng để dễ đọc và pythonicness.
Henry Gomersall

12

Theo mô tả của những người khác, một giải pháp nhanh và hiệu quả về không gian đang sử dụng numpy (np) với khả năng thao tác véc tơ tích hợp:

1. Với Numpy

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

2. Được tích hợp sẵn

2.1 Lambda

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

Lưu ý rằng map () hỗ trợ nhiều đối số.

2.2 zip và danh sách hiểu

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

1
+1 cho phương pháp lambda. Thật xấu hổ khi giải pháp này được kết hợp với các giải pháp khác được nhân đôi ở nơi khác.
LondonRob

10

numpyTheo ý kiến ​​của tôi thì đơn giản hơn :

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

Các kết quả:

Thi công thiết bị đầu cuối

Để biết thông tin chi tiết, kiểm tra tại đây: numpy.add


6

Có lẽ "cách pythonic nhất" nên bao gồm xử lý trường hợp trong đó list1 và list2 không cùng kích thước. Áp dụng một số phương pháp này sẽ lặng lẽ cho bạn một câu trả lời. Cách tiếp cận gọn gàng sẽ cho bạn biết, rất có thể với ValueError.

Thí dụ:

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)

Kết quả nào bạn có thể muốn nếu đây là một chức năng trong vấn đề của bạn?


trong trường hợp này một chắc chắn nên xem xét zip_longesttừ itertools với một fillvaluesố 0.
Ma0

6

Điều này thật đơn giản với 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])

Xem tài liệu ở đây

Nếu bạn muốn nhận một danh sách python:

result.tolist()

5

Điều này sẽ làm việc cho 2 danh sách trở lên; lặp qua danh sách các danh sách, nhưng sử dụng phép cộng gọn gàng để xử lý các phần tử của mỗi danh sách

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]

5

Có lẽ đây là pythonic và hơi hữu ích nếu bạn có một số lượng danh sách không xác định, và không nhập bất cứ thứ gì.

Miễn là các danh sách có cùng độ dài, bạn có thể sử dụng chức năng dưới đây.

Ở đây, * args chấp nhận một số lượng đối số danh sách khác nhau (nhưng chỉ tính tổng số phần tử giống nhau trong mỗi phần tử).

* Được sử dụng lại trong danh sách được trả về để giải nén các phần tử trong mỗi danh sách.

def sum_lists(*args):
    return list(map(sum, zip(*args)))

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

sum_lists(a,b)

Đầu ra:

[2, 4, 6]

Hoặc với 3 danh sách

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

Đầu ra:

[19, 19, 19, 19, 19]

3

Sử dụng bản đồ với chức năng lambda:

>>> map(lambda x, y: x + y, list1, list2)
[5, 7, 9]

3

Tôi đã không hẹn giờ nhưng tôi nghi ngờ việc này sẽ khá nhanh:

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

list_sum = (np.add(list1, list2)).tolist()

[5, 7, 9]


3
[list1[i] + list2[i] for i in range(len(list1))]

1
Nhiều pythonic sẽ là[a + b for (a, b) in zip(list1, list2)]
rayryeng

2

Mặc dù, câu hỏi thực tế không muốn lặp lại danh sách để tạo kết quả, nhưng tất cả các giải pháp đã được đề xuất thực hiện chính xác điều đó bên dưới mui xe!

Để làm mới: Bạn không thể thêm hai vectơ mà không nhìn vào tất cả các phần tử vectơ. Vì vậy, độ phức tạp thuật toán của hầu hết các giải pháp này là Big-O (n). Trong đó n là kích thước của vectơ.

Vì vậy, từ quan điểm thuật toán, sử dụng vòng lặp for để lặp lại việc tạo danh sách kết quả là hợp lý và pythonic cũng vậy. Tuy nhiên, ngoài ra, phương pháp này không có chi phí gọi hoặc nhập bất kỳ thư viện bổ sung nào.

# Assumption: The lists are of equal length.
resultList = [list1[i] + list2[i] for i in range(len(list1))]

Thời gian đang được hiển thị / thảo luận ở đây phụ thuộc vào hệ thống và triển khai và không thể là biện pháp đáng tin cậy để đo lường hiệu quả của hoạt động. Trong mọi trường hợp, độ phức tạp O lớn của phép toán cộng vector là tuyến tính, nghĩa là O (n).


1
a_list = []
b_list = []
for i in range(1,100):
    a_list.append(random.randint(1,100))

for i in range(1,100):
    a_list.append(random.randint(101,200))
[sum(x) for x in zip(a_list , b_list )]
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.