如何并行迭代两个列表?

2024-11-15 08:36:00
admin
原创
14
摘要:问题描述:我有两个可迭代对象,我想成对地对它们进行检查:foo = [1, 2, 3] bar = [4, 5, 6] for (f, b) in iterate_together(foo, bar): print("f:", f, " | b:", b) ...

问题描述:

我有两个可迭代对象,我想成对地对它们进行检查:

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

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


相关任务:

*如何将列表合并为一个元组列表? ——给定上述foobar,创建列表[(1, 4), (2, 5), (3, 6)]

*如何从单独的键和值列表创建字典(dict)? ——创建字典{1: 4, 2: 5, 3: 6}

*使用理解创建字典——在字典理解中dict使用构造。zip


解决方案 1:

Python 3

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

zip`foo当或较短者bar`停止时停止。

Python 3中,zip
像 Python2 一样,返回元组的迭代器itertools.izip。要获取元组列表,请使用list(zip(foo, bar))。要压缩直到两个迭代器都用尽,可以使用
itertools.zip_longest。

Python 2

Python 2中,zip
返回一个元组列表。当foobar不是很大时,这没问题。如果它们都很大,那么形成一个不必要的大临时变量,应该用或
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`barizip_longestNonefillvalueNone`


还要注意,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

解决方案 2:

您想要这个zip功能。

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

解决方案 3:

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

结果:

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

打印循环 1000 次

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

创建列表 - 1000reps

理解这些结果:

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

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

结论

zip()在创建过程中使用函数并行迭代两个列表可以获得显著的性能list。当并行迭代两个列表以打印出两个列表的元素时,该zip()函数将产生与函数类似的性能,与使用手动计数器变量、使用索引列表以及在特殊情况下(两个列表之一(或)enumerate()的元素可用于索引另一个列表)的性能相似。foo`bar`

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

解决方案 4:

您应该使用“ zip ”函数。以下是您自己的 zip 函数的示例

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

解决方案 5:

以下是使用列表推导式进行操作的方法:

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

解决方案 6:

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

解决方案 7:

zip()如果您想在使用迭代多个列表时保留索引,您可以将zip对象传递给enumerate()

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

例如,如果您想打印出两个列表中值不同的位置,您可以按如下方式进行。

foo, bar = ['a', 'b', 'c'], ['a', 'a', 'c']

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

如果您的列表长度不同,则zip()迭代直到最短列表结束。如果您想迭代直到最长列表结束,请使用zip_longest内置itertools模块。默认情况下,它会填充缺失值None(但您可以使用参数将其更改为您想要的任何值fillvalue)。

from itertools import zip_longest
for f, b in zip_longest(foo, bar):
    # do something

解决方案 8:

我们可以使用索引来迭代......

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

解决方案 9:

最有效的方法还是老方法。

import time

abc = list(range(10000000))
xyz = list(range(10000000))
start = time.time_ns()
for i in range(0, (len(abc)-1)):
    print("{} and {}".format(abc[i], xyz[i]))
print("Total time: {}".format(time.time_ns()-start))

时间:12315440476ns

import time

abc = list(range(10000000))
xyz = list(range(10000000))
start = time.time_ns()
for a, b in zip(abc, xyz):
    print("{} and {}".format(a, b))
print("Total time: {}".format(time.time_ns()-start))

时间:12338617143ns

相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   601  
  华为IPD与传统研发模式的8大差异在快速变化的商业环境中,产品研发模式的选择直接决定了企业的市场响应速度和竞争力。华为作为全球领先的通信技术解决方案供应商,其成功在很大程度上得益于对产品研发模式的持续创新。华为引入并深度定制的集成产品开发(IPD)体系,相较于传统的研发模式,展现出了显著的差异和优势。本文将详细探讨华为...
IPD流程是谁发明的   7  
  如何通过IPD流程缩短产品上市时间?在快速变化的市场环境中,产品上市时间成为企业竞争力的关键因素之一。集成产品开发(IPD, Integrated Product Development)作为一种先进的产品研发管理方法,通过其结构化的流程设计和跨部门协作机制,显著缩短了产品上市时间,提高了市场响应速度。本文将深入探讨如...
华为IPD流程   9  
  在项目管理领域,IPD(Integrated Product Development,集成产品开发)流程图是连接创意、设计与市场成功的桥梁。它不仅是一个视觉工具,更是一种战略思维方式的体现,帮助团队高效协同,确保产品按时、按质、按量推向市场。尽管IPD流程图可能初看之下显得错综复杂,但只需掌握几个关键点,你便能轻松驾驭...
IPD开发流程管理   8  
  在项目管理领域,集成产品开发(IPD)流程被视为提升产品上市速度、增强团队协作与创新能力的重要工具。然而,尽管IPD流程拥有诸多优势,其实施过程中仍可能遭遇多种挑战,导致项目失败。本文旨在深入探讨八个常见的IPD流程失败原因,并提出相应的解决方法,以帮助项目管理者规避风险,确保项目成功。缺乏明确的项目目标与战略对齐IP...
IPD流程图   8  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用