如何并行迭代两个列表?

时间:2009-11-02 21:26:24

标签: python iterator

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

但这对我来说似乎有点不合时宜。有没有更好的方法呢?

15 个答案:

答案 0 :(得分:1093)

for f, b in zip(foo, bar):
    print(f, b)
zipfoo中的较短者停止时,

bar会停止。

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)
izipfoo用尽时

bar停止。 当izip_longestfoo都用尽时,bar会停止。 当较短的迭代器耗尽时,izip_longest在与该迭代器对应的位置产生一个None的元组。如果您愿意,还可以在fillvalue之外设置不同的None。请参阅此处查看full story

Python 3 中,zip 返回元组的迭代器,如Python2中的itertools.izip。获取清单 元组,使用list(zip(foo, bar))。拉链直到两个迭代器都是 筋疲力尽,你会用 itertools.zip_longest


另请注意,zip及其zip - 类似于brethen可以接受任意数量的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

答案 1 :(得分:48)

您需要zip功能。

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

答案 2 :(得分:14)

内置zip完全符合您的要求。如果你想要相同的迭代而不是列表你可以看看itertools.izip,它做同样的事情,但一次给出一个结果。

答案 3 :(得分:12)

您要找的是zip

答案 4 :(得分:6)

您应该使用'zip'功能。以下是您自己的zip功能如何显示的示例

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

答案 5 :(得分:5)

zip功能解决了问题 文档:ZIP Library function

目标:将输出并排放置 问题:

#value1 is a list
value1 = driver.find_elements_by_class_name("review-text")
#value2 is a list
value2 = driver.find_elements_by_class_name("review-date")

for val1 in value1:
    print(val1.text)
    print "\n"
for val2 in value2:
    print(val2.text)
    print "\n"

输出:
     review1
     review2
     review3
     DATE1
     DATE2
     DATE3

解决方案:

for val1, val2 in zip(value1,value2):
    print (val1.text+':'+val2.text)
    print "\n"

输出:
review1:DATE1
review2:DATE2
review3:DATE3

答案 6 :(得分:3)

基于@unutbu的答案,我使用手动计数器比较了使用Python 3.6的zip()函数,Python的enumerate()函数时两个相同列表的迭代性能(请参阅count()函数),使用索引列表,以及在特殊情况下,可以使用两个列表之一(foobar)的元素对另一个列表进行索引清单。使用timeit()函数调查了它们在打印和创建新列表方面的性能,其中使用的重复次数为1000次。下面给出了我为执行这些调查而创建的Python脚本之一。 foobar列表的大小在10到1,000,000个元素之间。

结果:

  1. 出于打印目的:在考虑了+/- 5%的精度公差之后,观察到所有考虑的方法的性能与zip()函数近似相似。列表大小小于100个元素时发生异常。在这种情况下,索引列表方法比zip()函数稍慢,而enumerate()函数则快约9%。其他方法产生的性能与zip()函数相似。

    Print loop 1000 reps

  2. 用于创建列表:探索了两种类型的列表创建方法:使用(a)list.append()方法和(b)列表理解 。在考虑了+/- 5%的精度公差之后,对于这两种方法,发现zip()函数的执行速度都比enumerate()函数的执行速度快,而不是使用列表索引的执行速度,而不是手册的执行速度计数器。在这些比较中,zip()函数的性能提升可以快5%到60%。有趣的是,使用foo的元素索引bar可以产生与zip()函数相同或更快的性能(5%到20%)。

    Creating List - 1000reps

了解这些结果:

程序员必须确定有意义或有意义的每个操作的计算时间。

例如,出于打印目的,如果此时间标准为1秒,即10 ** 0秒,则在1秒处查看左侧的图的y轴,然后水平投影直至达到在单项曲线上,我们看到列表大小超过144个元素将导致大量的计算成本和对程序员的意义。也就是说,对于较小的列表大小,本研究中提到的方法所获得的任何性能对于程序员而言都是微不足道的。程序员将得出结论,zip()函数迭代打印语句的性能与其他方法相似。

结论

在创建zip()时,通过使用list函数在两个列表中并行地迭代可以获得显着的性能。当并行遍历两个列表以打印出两个列表的元素时,在使用手动计数器变量和使用索引方面,zip()函数的性能将与enumerate()函数相似。 -list,以及在特殊情况下可以使用两个列表之一(foobar)的元素来索引另一个列表的情况。

用于调查列表创建的Python3.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()

答案 7 :(得分:1)

您可以使用理解将第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))

答案 8 :(得分:0)

您可以在一本词典中使用3种类型:

def construct_dictionary_from_lists(names, ages, scores):
     end_str_dic = {}
     for item_name, item_age, score_item in zip(names, ages, scores):
         end_str_dic[item_name] = item_age, score_item
     return end_str_dic


print(
        construct_dictionary_from_lists(
            ["paul", "saul", "steve", "chimpy"],
            [28, 59, 22, 5], 
            [59, 85, 55, 60]
         )
      )

答案 9 :(得分:0)

为什么我们不能只使用索引来迭代..

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

答案 10 :(得分:-1)

制作一个 zip 对象,将元组的迭代列表从列表的元素中一一生成。

像这样 [ (arr1[0],arr2[0]), (arr1[1],arr2[1]), ....]

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

快乐编码。

答案 11 :(得分:-2)

以下是列表理解方法:

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

答案 12 :(得分:-2)

Python3参考

itertools — Functions creating iterators for efficient looping

multiprocessing

from itertools import zip_longest
from multiprocessing.dummy import Pool as ThreadPool

try:
    l1 = [1, 2, 3, 4, 5, 6, 7]
    l2 = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']

    def f(x):
        print(x)

    pool = ThreadPool()
    zipped = list(zip_longest(l1, l2, fillvalue='na'))
    results = pool.map(f, zipped)
    pool.close()
    pool.join()    
except Exception as e:
    print(e)

答案 13 :(得分:-2)

Python 3:

import itertools as it

for foo, bar in list(it.izip_longest(list1, list2)):
    print(foo, bar)

答案 14 :(得分:-3)

def ncustom_zip(seq1,seq2,max_length):
        length= len(seq1) if len(seq1)>len(seq2) else len(seq2) if max_length else len(seq1) if len(seq1)<len(seq2) else len(seq2)
        for i in range(length):
                x= seq1[i] if len(seq1)>i else None  
                y= seq2[i] if len(seq2)>i else None
                yield x,y


l=[12,2,3,9]
p=[89,8,92,5,7]

for i,j in ncustom_zip(l,p,True):
        print i,j
for i,j in ncustom_zip(l,p,False):
        print i,j