簡體   English   中英

如何並行遍歷兩個列表?

[英]How do I iterate through two lists in parallel?

我有兩個可迭代對象,我想成對對它們進行 go:

foo = [1, 2, 3]
bar = [4, 5, 6]

for (f, b) in iterate_together(foo, bar):
    print("f:", f, " |  b:", b)

這應該導致:

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

一種方法是遍歷索引:

for i in range(len(foo)):
    print("f:", foo[i], " |  b:", bar[i])

但這對我來說似乎有點 unpythonic。 有更好的方法嗎?

蟒蛇 3

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

foobar中較短的一個停止時, zip停止。

Python 3中, zip返回元組的迭代器,如 Python2 中的itertools.izip 要獲取元組列表,請使用list(zip(foo, bar)) 要壓縮直到兩個迭代器都用完,您將使用itertools.zip_longest

蟒蛇2

Python 2中, zip返回一個元組列表。 foobar不是很大時,這很好。 如果它們都是巨大的,那么形成zip(foo,bar)是一個不必要的巨大臨時變量,應該用itertools.izipitertools.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)

izipfoobar用盡時停止。 izip_longestfoobar都用盡時停止。 當較短的迭代器用盡時, izip_longest在對應於該迭代器的位置產生一個具有None的元組。 如果您願意,您還可以設置除None之外的其他fillvalue 完整的故事請看這里。


另請注意, zip及其類似zip的 brethen 可以接受任意數量的迭代作為參數。 例如,

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

你想要zip功能。

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

你應該使用' zip '功能。 這是您自己的 zip 函數的示例

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

@unutbu的答案的基礎上,我比較了兩個相同列表在使用 Python 3.6 的zip()函數、Python 的enumerate()函數、使用手動計數器(參見count()函數)、使用索引時的迭代性能-list,以及在兩個列表之一( foobar )的元素可用於索引另一個列表的特殊情況下。 使用timeit()函數分別研究了它們在打印和創建新列表方面的性能,其中使用的重復次數為 1000 次。 下面給出了我為執行這些調查而創建的 Python 腳本之一。 foobar列表的大小范圍從 10 到 1,000,000 個元素。

結果:

  1. 出於打印目的:在考慮 +/-5% 的精度容差后,觀察到所有考慮的方法的性能與zip()函數大致相似。 當列表大小小於 100 個元素時發生異常。 在這種情況下,index-list 方法比zip()函數稍慢,而enumerate()函數要快約 9%。 其他方法產生了與zip()函數類似的性能。

    打印循環 1000 次

  2. 用於創建列表:探索了兩種類型的列表創建方法:使用 (a) list.append()方法和 (b)列表理解 在考慮到 +/-5% 的精度容差后,對於這兩種方法,發現zip() enumerate()比使用列表索引的函數比使用手動計數器執行得更快。 在這些比較中, zip()函數的性能增益可以快 5% 到 60%。 有趣的是,使用foo的元素來索引bar可以產生與zip()函數相同或更快的性能(5% 到 20%)。

    創建列表 - 1000 次

理解這些結果:

程序員必須確定每個有意義或有意義的操作的計算時間量。

例如,出於打印目的,如果此時間標准為 1 秒,即 10**0 秒,則查看左側 1 秒處圖形的 y 軸並將其水平投影,直到到達單項式曲線,我們看到超過 144 個元素的列表大小將產生大量的計算成本和對程序員的重要性。 也就是說,本調查中提到的針對較小列表大小的方法所獲得的任何性能對程序員來說都是微不足道的。 程序員將得出結論, zip()函數迭代打印語句的性能與其他方法相似。

結論

在創建list期間使用zip()函數並行遍歷兩個列表可以獲得顯着的性能。 當並行遍歷兩個列表以打印出兩個列表的元素時, zip()函數將產生與enumerate()函數相似的性能,如使用手動計數器變量、使用索引列表,以及至於在兩個列表( foobar )之一的元素可用於索引另一個列表的特殊情況下。

用於調查列表創建的 Python 3.6 腳本。

import timeit
import matplotlib.pyplot as plt
import numpy as np


def test_zip( foo, bar ):
    store = []
    for f, b in zip(foo, bar):
        #print(f, b)
        store.append( (f, b) )

def test_enumerate( foo, bar ):
    store = []
    for n, f in enumerate( foo ):
        #print(f, bar[n])
        store.append( (f, bar[n]) )

def test_count( foo, bar ):
    store = []
    count = 0
    for f in foo:
        #print(f, bar[count])
        store.append( (f, bar[count]) )
        count += 1

def test_indices( foo, bar, indices ):
    store = []
    for i in indices:
        #print(foo[i], bar[i])
        store.append( (foo[i], bar[i]) )

def test_existing_list_indices( foo, bar ):
    store = []
    for f in foo:
        #print(f, bar[f])
        store.append( (f, bar[f]) )


list_sizes = [ 10, 100, 1000, 10000, 100000, 1000000 ]
tz = []
te = []
tc = []
ti = []
tii= []

tcz = []
tce = []
tci = []
tcii= []

for a in list_sizes:
    foo = [ i for i in range(a) ]
    bar = [ i for i in range(a) ]
    indices = [ i for i in range(a) ]
    reps = 1000

    tz.append( timeit.timeit( 'test_zip( foo, bar )',
                              'from __main__ import test_zip, foo, bar',
                              number=reps
                              )
               )
    te.append( timeit.timeit( 'test_enumerate( foo, bar )',
                              'from __main__ import test_enumerate, foo, bar',
                              number=reps
                              )
               )
    tc.append( timeit.timeit( 'test_count( foo, bar )',
                              'from __main__ import test_count, foo, bar',
                              number=reps
                              )
               )
    ti.append( timeit.timeit( 'test_indices( foo, bar, indices )',
                              'from __main__ import test_indices, foo, bar, indices',
                              number=reps
                              )
               )
    tii.append( timeit.timeit( 'test_existing_list_indices( foo, bar )',
                               'from __main__ import test_existing_list_indices, foo, bar',
                               number=reps
                               )
                )

    tcz.append( timeit.timeit( '[(f, b) for f, b in zip(foo, bar)]',
                               'from __main__ import foo, bar',
                               number=reps
                               )
                )
    tce.append( timeit.timeit( '[(f, bar[n]) for n, f in enumerate( foo )]',
                               'from __main__ import foo, bar',
                               number=reps
                               )
                )
    tci.append( timeit.timeit( '[(foo[i], bar[i]) for i in indices ]',
                               'from __main__ import foo, bar, indices',
                               number=reps
                               )
                )
    tcii.append( timeit.timeit( '[(f, bar[f]) for f in foo ]',
                                'from __main__ import foo, bar',
                                number=reps
                                )
                 )

print( f'te  = {te}' )
print( f'ti  = {ti}' )
print( f'tii = {tii}' )
print( f'tc  = {tc}' )
print( f'tz  = {tz}' )

print( f'tce  = {te}' )
print( f'tci  = {ti}' )
print( f'tcii = {tii}' )
print( f'tcz  = {tz}' )

fig, ax = plt.subplots( 2, 2 )
ax[0,0].plot( list_sizes, te, label='enumerate()', marker='.' )
ax[0,0].plot( list_sizes, ti, label='index-list', marker='.' )
ax[0,0].plot( list_sizes, tii, label='element of foo', marker='.' )
ax[0,0].plot( list_sizes, tc, label='count()', marker='.' )
ax[0,0].plot( list_sizes, tz, label='zip()', marker='.')
ax[0,0].set_xscale('log')
ax[0,0].set_yscale('log')
ax[0,0].set_xlabel('List Size')
ax[0,0].set_ylabel('Time (s)')
ax[0,0].legend()
ax[0,0].grid( b=True, which='major', axis='both')
ax[0,0].grid( b=True, which='minor', axis='both')

ax[0,1].plot( list_sizes, np.array(te)/np.array(tz), label='enumerate()', marker='.' )
ax[0,1].plot( list_sizes, np.array(ti)/np.array(tz), label='index-list', marker='.' )
ax[0,1].plot( list_sizes, np.array(tii)/np.array(tz), label='element of foo', marker='.' )
ax[0,1].plot( list_sizes, np.array(tc)/np.array(tz), label='count()', marker='.' )
ax[0,1].set_xscale('log')
ax[0,1].set_xlabel('List Size')
ax[0,1].set_ylabel('Performances ( vs zip() function )')
ax[0,1].legend()
ax[0,1].grid( b=True, which='major', axis='both')
ax[0,1].grid( b=True, which='minor', axis='both')

ax[1,0].plot( list_sizes, tce, label='list comprehension using enumerate()',  marker='.')
ax[1,0].plot( list_sizes, tci, label='list comprehension using index-list()',  marker='.')
ax[1,0].plot( list_sizes, tcii, label='list comprehension using element of foo',  marker='.')
ax[1,0].plot( list_sizes, tcz, label='list comprehension using zip()',  marker='.')
ax[1,0].set_xscale('log')
ax[1,0].set_yscale('log')
ax[1,0].set_xlabel('List Size')
ax[1,0].set_ylabel('Time (s)')
ax[1,0].legend()
ax[1,0].grid( b=True, which='major', axis='both')
ax[1,0].grid( b=True, which='minor', axis='both')

ax[1,1].plot( list_sizes, np.array(tce)/np.array(tcz), label='enumerate()', marker='.' )
ax[1,1].plot( list_sizes, np.array(tci)/np.array(tcz), label='index-list', marker='.' )
ax[1,1].plot( list_sizes, np.array(tcii)/np.array(tcz), label='element of foo', marker='.' )
ax[1,1].set_xscale('log')
ax[1,1].set_xlabel('List Size')
ax[1,1].set_ylabel('Performances ( vs zip() function )')
ax[1,1].legend()
ax[1,1].grid( b=True, which='major', axis='both')
ax[1,1].grid( b=True, which='minor', axis='both')

plt.show()

您可以使用理解將第 n 個元素捆綁到元組或列表中,然后使用生成器函數將它們傳遞出去。

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

這是使用列表理解的方法:

a = (1, 2, 3)
b = (4, 5, 6)
[print('f:', i, '; b', j) for i, j in zip(a, b)]

它打印:

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

我們可以只使用索引來迭代......

foo = ['a', 'b', 'c']
bar = [10, 20, 30]
for indx, itm in enumerate(foo):
    print (foo[indx], bar[indx])

如果要在使用zip()一起迭代多個列表時保留索引,可以將zip object 傳遞給enumerate()

for i, (f, b) in enumerate(zip(foo, bar)):
    # do something

例如,如果您想打印出 2 個列表中值不同的位置,您可以執行以下操作。

foo, bar = [*'abc'], [*'aac']

for i, (f, b) in enumerate(zip(foo, bar)):
    if f != b:
        print(f"items at index {i} are different")
    
# items at index 1 are different

與任何python版本

while a and b: # condition may change when length not equal
   ae, be = a.pop(0), b.pop(0) 
   print(f"{ae} {be}") # check if None

制作一個 zip 對象,該對象將元組的迭代列表從列表的元素中一一生成。

像這樣 [ (arr1[0],arr2[0]), (arr1[1],arr2[1]), ....]

result=zip(arr1,arr2)
for res in result:
     print(res[0],res[1])

快樂編碼。

我在 Python 中有兩個可迭代對象,我想成對地討論它們:

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 range(len(foo)):
    print("f: ", foo[i], "; b: ", bar[i])

但這對我來說似乎有點不合邏輯。 有沒有更好的方法來做到這一點?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM