วิธีการวนซ้ำสองรายการในแบบคู่ขนานได้อย่างไร


862

ฉันมีสอง iterables ในหลามและฉันต้องการไปพวกเขาเป็นคู่:

foo = (1, 2, 3)
bar = (4, 5, 6)

for (f, b) in some_iterator(foo, bar):
    print "f: ", f, "; b: ", b

มันควรจะส่งผลใน:

f: 1; b: 4
f: 2; b: 5
f: 3; b: 6

วิธีหนึ่งในการทำเช่นนี้คือการย้ำเหนือดัชนี:

for i in xrange(len(foo)):
    print "f: ", foo[i], "; b: ", b[i]

แต่ดูเหมือนว่าฉันจะไม่ได้เน้นเสียง มีวิธีที่ดีกว่าที่จะทำหรือไม่

คำตอบ:


1351

Python 3

for f, b in zip(foo, bar):
    print(f, b)

zipหยุดเมื่อสั้นfooหรือbarหยุด

ในหลาม 3 , zip ส่งกลับ iterator ของ tuples เช่นitertools.izipใน Python2 ที่จะได้รับรายชื่อของ tuples list(zip(foo, bar))ใช้ และเพื่อซิปจนกว่าทั้ง iterators ถูกใช้จนหมดคุณจะใช้ itertools.zip_longest

Python 2

ในหลาม 2 , zip กลับรายการของ tuples นี่เป็นสิ่งที่ดีเมื่อfooและbarไม่ใหญ่ หากทั้งคู่มีขนาดใหญ่แล้วการขึ้นรูปzip(foo,bar)เป็นตัวแปรชั่วคราวที่มีขนาดใหญ่เกินความจำเป็นและควรถูกแทนที่ด้วยitertools.izipหรือ itertools.izip_longestซึ่งจะส่งคืนตัววนซ้ำแทนรายการ

import itertools
for f,b in itertools.izip(foo,bar):
    print(f,b)
for f,b in itertools.izip_longest(foo,bar):
    print(f,b)

izipหยุดเมื่อใดfooหรือbarหมด izip_longestหยุดเมื่อทั้งสองfooและbarหมด เมื่อตัววนซ้ำที่สั้นลงหมดลงizip_longestจะให้ผลลัพธ์เป็น tuple Noneในตำแหน่งที่สอดคล้องกับตัววนซ้ำนั้น คุณสามารถตั้งค่าfillvalueอื่นนอกเหนือจากที่Noneคุณต้องการ ดูที่นี่สำหรับเรื่องราวทั้งหมด


โปรดทราบว่าzipและzipพี่น้องที่คล้ายกันของมันสามารถยอมรับจำนวน iterables โดยพลการเป็นข้อโต้แย้ง ตัวอย่างเช่น,

for num, cheese, color in zip([1,2,3], ['manchego', 'stilton', 'brie'], 
                              ['red', 'blue', 'green']):
    print('{} {} {}'.format(num, color, cheese))

พิมพ์

1 red manchego
2 blue stilton
3 green brie

@unutbu ทำไมฉันถึงชอบวิธีการของ OP มากกว่าizipหนึ่งวิธี (แม้ว่าizip/ zipดูจะดูดีกว่า)?
แขนเสื้อ

3
คุณอาจต้องการพูดถึง Python 3 ก่อนเพราะอาจพิสูจน์ได้ในอนาคต นอกจากนี้มันยังมีค่าที่ชี้ให้เห็นว่าใน Python 3 zip () มีข้อได้เปรียบตรงที่ itertools.izip () เท่านั้นที่มีใน Python 2 ดังนั้นจึงเป็นวิธีที่จะไป
Daniel S.

3
ผมอาจจะขอให้คุณปรับปรุงคำตอบของคุณอย่างชัดเจนว่ารัฐzipและzipเหมือนฟังก์ชั่นจากitertoolsยอมรับจำนวน iterables ใด ๆ และไม่ได้เป็นเพียง 2? คำถามนี้เป็นที่ยอมรับในขณะนี้และคำตอบของคุณคือการอัปเดตเดียวที่คุ้มค่า
vaultah

นอกจากนี้สิ่งที่ถ้าฉันต้องการดัชนีi? ฉันสามารถใส่รหัสไปรษณีย์ในการแจกแจงได้หรือไม่?
Charlie Parker

2
@CharlieParker: ใช่คุณสามารถ for i, (f, b) in enumerate(zip(foo, bar))แต่แล้วคุณจะใช้
unutbu

60

คุณต้องการzipฟังก์ชั่น

for (f,b) in zip(foo, bar):
    print "f: ", f ,"; b: ", b

11
ก่อน Python 3.0 คุณต้องการใช้itertools.izipถ้าคุณมีองค์ประกอบจำนวนมาก
Georg Schölly

15

คุณควรใช้ฟังก์ชั่น ' zip ' ต่อไปนี้เป็นตัวอย่างลักษณะการทำงานของซิปของคุณ

def custom_zip(seq1, seq2):
    it1 = iter(seq1)
    it2 = iter(seq2)
    while True:
        yield next(it1), next(it2)

สิ่งนี้ไม่ได้มีผลลัพธ์เหมือนกันทุกประการzip(seq1, seq2)ใช่หรือไม่
Niklas Mertsch

@NiklasMertsch ใช่มันมีผลลัพธ์เหมือนกันทุกประการ ฉันเพิ่งยกตัวอย่างลักษณะของฟังก์ชัน zip
Vlad Bezden

0

คุณสามารถรวมองค์ประกอบที่ n ลงใน tuple หรือรายการโดยใช้ความเข้าใจแล้วส่งออกไปพร้อมกับฟังก์ชันตัวสร้าง

def iterate_multi(*lists):
    for i in range(min(map(len,lists))):
        yield tuple(l[i] for l in lists)

for l1, l2, l3 in iterate_multi([1,2,3],[4,5,6],[7,8,9]):
    print(str(l1)+","+str(l2)+","+str(l3))

-2

ในกรณีที่มีใครบางคนกำลังมองหาสิ่งนี้ฉันพบว่ามันง่ายและสะดวก:

list_1 = ["Hello", "World"]
list_2 = [1, 2, 3]

for a,b in [(list_1, list_2)]:
    for element_a in a:
        ...
    for element_b in b:
        ...

>> Hello
World
1
2
3

รายการจะมีการทำซ้ำกับเนื้อหาเต็มของพวกเขาซึ่งแตกต่างจากzip ()ซึ่งซ้ำเท่านั้นถึงความยาวเนื้อหาขั้นต่ำ


ผู้ลงคะแนนเสียงควรแสดงความคิดเห็นเกี่ยวกับสิ่งที่พวกเขาพบว่าผิดกับวิธีการของฉันหรือถ้ามันไม่เหมาะกับวิธีแก้ปัญหาที่เป็นไปได้สำหรับคำถามนี้
VladiC4T

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.