Làm thế nào để lặp qua hai danh sách song song?


863

Tôi có hai lần lặp trong Python và tôi muốn đi qua chúng theo cặp:

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

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

Nó sẽ dẫn đến:

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

Một cách để làm điều đó là lặp đi lặp lại qua các chỉ số:

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

Nhưng điều đó có vẻ hơi khó chịu đối với tôi. Có cách nào tốt hơn để làm điều đó?

Câu trả lời:


1352

Con trăn 3

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

zipdừng lại khi ngắn hơn foohoặc bardừng lại.

Trong Python 3 , zip trả về một iterator của các bộ dữ liệu, như itertools.iziptrong Python2. Để có được một danh sách các bộ dữ liệu, sử dụng list(zip(foo, bar)). Và để nén cho đến khi cả hai trình lặp hết, bạn sẽ sử dụng itertools.zip_longest .

Con trăn 2

Trong Python 2 , zip trả về một danh sách các bộ dữ liệu. Điều này là tốt khi foobarkhông lớn. Nếu cả hai đều lớn thì hình thành zip(foo,bar)là một biến tạm thời lớn không cần thiết và nên được thay thế bằng itertools.iziphoặc itertools.izip_longest, trả về một trình vòng lặp thay vì danh sách.

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)

izipdừng lại khi foohoặc barlà hết izip_longestdừng lại khi cả hai foobarkiệt sức. Khi (các) trình lặp ngắn hơn đã hết, izip_longestsẽ tạo ra một tuple với Nonevị trí tương ứng với trình vòng lặp đó. Bạn cũng có thể thiết lập một sự khác biệt fillvaluebên cạnh Nonenếu bạn muốn. Xem ở đây để biết toàn bộ câu chuyện .


Cũng lưu ý rằng zipvà anh em zipgiống như nó có thể chấp nhận một số lượng lặp tùy ý làm đối số. Ví dụ,

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

in

1 red manchego
2 blue stilton
3 green brie

@unutbu Tại sao tôi thích phương thức của OP hơn phương thức này izip(mặc dù izip/ ziptrông sạch hơn nhiều)?
armundle 14/03/2016

3
Bạn có thể muốn đề cập đến Python 3 trước tiên, vì nó có thể là bằng chứng trong tương lai nhiều hơn. Hơn nữa, đáng để chỉ ra rằng trong Python 3, zip () có chính xác lợi thế mà chỉ itertools.izip () có trong Python 2 và do đó, nó thường là cách để đi.
Daniel S.

3
Tôi có thể yêu cầu bạn cập nhật câu trả lời của mình để nói rõ rằng các hàm giống zipzipkhông itertoolschấp nhận bất kỳ số lần lặp nào và không chỉ 2 không? Câu hỏi này là hợp quy bây giờ và câu trả lời của bạn là duy nhất đáng để cập nhật.
vaultah

Nếu tôi muốn chỉ số ithì sao? Tôi có thể bọc cái zip đó trong bảng liệt kê không?
Charlie Parker

2
@CharlieParker: Có, bạn có thể, nhưng sau đó bạn sẽ sử dụng for i, (f, b) in enumerate(zip(foo, bar)).
unutbu

60

Bạn muốn zipchức năng.

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

11
Trước Python 3.0 bạn muốn sử dụng itertools.izipnếu bạn có số lượng lớn các phần tử.
Georg Schölly

15

Bạn nên sử dụng chức năng ' zip '. Dưới đây là một ví dụ về cách chức năng zip của riêng bạn có thể trông như thế nào

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

Điều này không có kết quả chính xác như zip(seq1, seq2)?
Niklas Mertsch

@NiklasMertsch vâng, nó có kết quả chính xác như nhau. Tôi vừa cung cấp ví dụ về chức năng zip trông như thế nào
Vlad Bezden

0

Bạn có thể bó các phần tử thứ n vào một tuple hoặc danh sách bằng cách hiểu, sau đó chuyển chúng ra với hàm tạo.

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

Trong trường hợp ai đó đang tìm kiếm thứ gì đó như thế này, tôi thấy nó rất đơn giản và dễ dàng:

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

Các danh sách sẽ được lặp lại với nội dung đầy đủ của chúng, không giống như zip () chỉ lặp lại tối đa nội dung tối thiểu.


downvoters nên bình luận về những gì họ thấy sai với cách tiếp cận của tôi hoặc nếu nó không phù hợp như một giải pháp khả thi cho câu hỏi này.
VladiC4T

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.