องค์ประกอบที่ชาญฉลาดของ 2 รายการ?


244

ฉันมีตอนนี้:

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

ฉันต้องการที่จะมี:

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

เป็นเพียงการเพิ่มองค์ประกอบสองรายการอย่างชาญฉลาด

แน่นอนฉันสามารถย้ำสองรายการ แต่ฉันไม่ต้องการทำอย่างนั้น

คืออะไร วิธีที่ Pythonic ที่สุดของการทำเพื่อ?


คำตอบ:


364

ใช้mapกับoperator.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

10
หากคุณใช้อาร์เรย์ขนาดใหญ่เหล่านั้นโซลูชัน numpy โดย @BasSwinckels น่าจะเป็นสิ่งที่คุณควรดู
Henry Gomersall

1
คุณใช้ Python เวอร์ชันใดในการกำหนดเวลาเหล่านั้น
arshajii

9
NB - ใน python3, map () ส่งคืนสิ่งที่ซ้ำได้มากกว่ารายการ หากคุณต้องการรายการจริงคำตอบแรกคือรายการ (แผนที่ (เพิ่ม, รายการ 1, รายการ 2))
FLHerne

การสังเกตปัญหา python3 ที่บันทึกโดย @FLHerne ด้วยmapจะเพิ่มความสำคัญมากขึ้นเมื่อเวลาผ่านไป Python 2 จะสูญเสียการสนับสนุนอย่างเป็นทางการในเวลาน้อยกว่า 3 ปี
nealmcb

1
มีหลายครั้งที่ไวยากรณ์ของงูใหญ่สง่างามและเรียบง่าย แต่น่าเสียดายที่นี่ไม่ใช่หนึ่งในนั้น และสำหรับงานง่าย ๆ มันเป็นเรื่องน่าเสียดาย .... ทำไมพวกเขาถึงทำให้ "+" เรียงรายการต่าง ๆ เมื่อมีวิธีการ. extend () อยู่แล้ว?
Nic Scozzaro

105

คนอื่น ๆ ยกตัวอย่างว่าจะทำอย่างไรกับงูหลามบริสุทธิ์ หากคุณต้องการทำสิ่งนี้ด้วยอาร์เรย์ที่มีอิลิเมนต์ 100.000 คุณควรใช้ 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 มาตรฐาน (และฉันพบว่าเวอร์ชันของ Pythonic ของ Henry เป็นรุ่นที่ดีที่สุด) หากคุณกำลังเข้าสู่ภาวะวิกฤตจำนวนมากให้numpyทำการยกของหนัก สำหรับ freaks ความเร็ว: มันดูเหมือนว่าวิธีการแก้ปัญหา numpy n = 8เร็วเริ่มรอบ


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

4
@deltab คำตอบที่ยอมรับนั้นเร็วขึ้นและมันมีคำตอบนี้ (ข้อมูลเพิ่มเติม)
การพนัน Sibbs

2
@ perfectionm1ng แม้ว่าฉันจะเข้าใจประเด็นของคุณ (และอย่าบ่นเลยสักนิด) ฉันแค่คิดว่ามันคุ้มค่าที่จะชี้ให้เห็นว่าฉันจะใช้วิธีแก้ปัญหาที่ฉันนำเสนออยู่เสมอ (ซึ่งไม่ต้องนำเข้าเลย เป็นเนื้อหาที่ pythonic เพิ่มเติม) หรือที่นับความเร็วคำตอบของBas Swinckelซึ่งเป็นทางเลือกที่ถูกต้องซึ่งเป็นเรื่องสำคัญที่ความเร็วมีความสำคัญ
Henry Gomersall

ใช่. ขอบคุณสำหรับความคิดเห็น แต่โดยพื้นฐาน[sum(x) for x in zip(list1, list2)]แล้วเหมือนกับคำตอบของคุณใช่ไหม? :)
การพนัน Sibbs

4
@ perfectionm1ng มากกว่าหรือน้อยกว่า (แม้ว่าจะถูกเพิ่มเข้ามาหลังจากที่ฉันแก้ไข :) โดยส่วนตัวแล้วฉันชอบสัญกรณ์ a + b ที่มี tuple ที่เปิดออกมาอย่างชัดเจนสำหรับการอ่านและ pythonicness
Henry Gomersall

12

ตามที่อธิบายโดยคนอื่น ๆ โซลูชันที่รวดเร็วและมีประสิทธิภาพในพื้นที่กำลังใช้ numpy (np) ด้วยความสามารถในการจัดการเวกเตอร์ในตัว:

1. ด้วย Numpy

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

2. ด้วยบิวด์อิน

2.1 แลมบ์ดา

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

ขอให้สังเกตว่า map () รองรับการขัดแย้งหลายข้อ

2.2 zip และ list comprehension

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

1
+1 สำหรับแนวทางแลมบ์ดา น่าเสียดายที่โซลูชันนี้รวมกับโซลูชันอื่นซึ่งทำซ้ำที่อื่น
LondonRob

10

มันง่ายกว่าที่จะใช้numpyจากความคิดของฉัน:

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

ผล:

การทำงานของเทอร์มินัล

สำหรับข้อมูลพารามิเตอร์โดยละเอียดโปรดตรวจสอบที่นี่: numpy.add


6

บางที "วิธี 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)

ผลลัพธ์ใดที่คุณอาจต้องการหากนี่เป็นหน้าที่ของคุณ


ในกรณีนี้อย่างใดอย่างหนึ่งแน่นอนควรมีลักษณะเป็นzip_longestจาก itertools กับของfillvalue 0
Ma0

6

แบบนี้ง่ายด้วย 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])

ดูเอกสารที่นี่

หากคุณต้องการรับรายการไพ ธ อน:

result.tolist()

5

สิ่งนี้จะใช้ได้กับ 2 รายการขึ้นไป วนซ้ำผ่านรายการของรายการ แต่ใช้การเพิ่ม 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]

5

บางทีนี่อาจเป็น pythonic และมีประโยชน์เล็กน้อยหากคุณมีรายการที่ไม่รู้จักจำนวนมากและไม่มีการนำเข้าอะไรเลย

ตราบใดที่รายการมีความยาวเท่ากันคุณสามารถใช้ฟังก์ชันด้านล่าง

ที่นี่ * args ยอมรับจำนวนตัวแปรของรายการอาร์กิวเมนต์ (แต่จะรวมจำนวนองค์ประกอบเดียวกันในแต่ละรายการเท่านั้น)

The * จะใช้อีกครั้งในรายการที่ส่งคืนเพื่อคลายองค์ประกอบในแต่ละรายการ

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]


3

ฉันยังไม่ได้ตั้งเวลา แต่ฉันคิดว่ามันจะค่อนข้างเร็ว:

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

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

[5, 7, 9]

3

หากคุณต้องการจัดการรายการขนาดแตกต่างกันไม่ต้องกังวล! คุณมีโมดูล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ใช้

ดูเพิ่มเติมคำตอบที่เกี่ยวข้องนี้และแสดงความคิดเห็นในคำถามอื่น



2

แม้ว่าคำถามที่เกิดขึ้นจริงไม่ต้องการวนซ้ำในรายการเพื่อสร้างผลลัพธ์ แต่การแก้ปัญหาทั้งหมดที่ได้รับการเสนอนั้นไม่ได้อยู่ภายใต้ประทุน!

วิธีรีเฟรช: คุณไม่สามารถเพิ่มเวกเตอร์สองตัวโดยไม่ดูองค์ประกอบเวกเตอร์ทั้งหมด ดังนั้นความซับซ้อนของอัลกอริธึมในการแก้ปัญหาส่วนใหญ่คือ Big-O (n) โดยที่ n คือมิติของเวกเตอร์

ดังนั้นจากมุมมองของอัลกอริทึมการใช้ a สำหรับลูปไปยังวนซ้ำสร้างรายการผลลัพธ์เป็นตรรกะและ pythonic เกินไป อย่างไรก็ตามนอกจากนี้วิธีนี้ไม่มีค่าใช้จ่ายในการโทรหรือนำเข้าห้องสมุดเพิ่มเติมใด ๆ

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

เวลาที่แสดง / อภิปรายในที่นี้เป็นระบบและการนำไปใช้งานและไม่สามารถวัดได้อย่างน่าเชื่อถือในการวัดประสิทธิภาพของการดำเนินการ ในกรณีใด ๆ ความซับซ้อน O ขนาดใหญ่ของการดำเนินการเพิ่มเวกเตอร์เป็นแบบเชิงเส้นหมายถึง 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 )]
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.