සමාන්තරව ලැයිස්තු දෙකක් හරහා නැවත ක්‍රියා කරන්නේ කෙසේද?


913

මට පයිතන්හි පුනරාවර්තන දෙකක් තිබේ, මට ඒවා යුගල වශයෙන් යාමට අවශ්‍යයි:

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

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

එහි ප්‍රති result ලය විය යුත්තේ:

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]

නමුත් එය මට තරමක් අප්‍රසන්න බවක් පෙනේ. එය කිරීමට වඩා හොඳ ක්‍රමයක් තිබේද?

Answers:


1425

පයිතන් 3

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

zipකෙටි fooහෝ barනතර වූ විට නතර වේ.

දී Python 3 , zip වැනි, tuples ක iterator නැවත itertools.izipPython2 දී. ටුපල් ලැයිස්තුවක් ලබා ගැනීමට, භාවිතා කරන්න list(zip(foo, bar)). පුනරාවර්තකයන් දෙකම අවසන් වන තුරු zip කිරීමට, ඔබ itertools.zip_longest භාවිතා කරයි .

පයිතන් 2

දී Python 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වෙහෙස වේ. කෙටි iterator (ව) වෙහෙසට පත් වූ විට, izip_longestසමග tuple හික්මුණු Noneබව iterator අනුරූප තත්වයක. ඔබට අවශ්‍ය නම් ඊට fillvalueඅමතරව වෙනත් දෙයක් සැකසිය හැකිය None. සම්පූර්ණ කතාව සඳහා මෙහි බලන්න .


තවද, ඒ zipහා zipසමාන බ්‍රෙටන්ට අත්තනෝමතික පුනරාවර්තන සංඛ්‍යාවක් තර්ක ලෙස පිළිගත හැකි බව සලකන්න . උදාහරණයක් වශයෙන්,

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

utunutbu මම ක්‍රමයට වඩා OP ක්‍රමයට කැමති ඇයි izip( izip/ zipවඩා පිරිසිදු පෙනුමක් තිබුණත් )?
අවි ආයුධ

3
ඔබට පළමුව පයිතන් 3 සඳහන් කිරීමට අවශ්‍ය විය හැකිය, මන්ද එය අනාගතයට වඩා සාධනයකි. එපමණක් නොව, පයිතන් 3 හි සිප් () ට හරියටම වාසියක් ඇත්තේ ඉතර්ටූල්ස්.ඉසිප් () ට පමණක් පයිතන් 2 හි ඇති බව පෙන්වා දීම වටී. එබැවින් එය සාමාන්‍යයෙන් යා යුතු මාර්ගය වේ.
ඩැනියෙල් එස්.

4
2 ක් පමණක් නොව, නැවත නැවත කළ හැකි සංඛ්‍යාවක් පිළිගැනීමෙන් zipහා ඒ හා zipසමාන කාර්යයන් පැහැදිලිව ප්‍රකාශ කිරීම සඳහා ඔබේ පිළිතුර යාවත්කාලීන කරන ලෙස මම ඔබෙන් ඉල්ලා සිටිමි. itertoolsමෙම ප්‍රශ්නය දැන් කැනොනිකල් වන අතර යාවත්කාලීන කිරීම වටී ඔබේ පිළිතුර පමණි.
vaultah

ඊට අමතරව මට දර්ශකය අවශ්‍ය නම් කුමක් කළ iයුතුද? මට එම සිප් එක ගණන් කළ හැකි ද?
චාලි පාකර්

2
Har චාර්ලිපාර්කර්: ඔව් ඔබට පුළුවන්, නමුත් පසුව ඔබ භාවිතා කරයි for i, (f, b) in enumerate(zip(foo, bar)).
unutbu

63

ඔබට zipකාර්යය අවශ්‍යයි .

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

11
පයිතන් 3.0 ට පෙර itertools.izipඔබට විශාල මූලද්‍රව්‍ය තිබේ නම් භාවිතා කිරීමට අවශ්‍යය .
ජෝර්ජ් ෂෝලි

17

ඔබ ' zip ' ශ්‍රිතය භාවිතා කළ යුතුය . මෙන්න ඔබේම සිප් ශ්‍රිතය කෙසේ විය හැකිද යන්න පිළිබඳ උදාහරණයකි

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

මෙය හරියටම සමාන ප්‍රති result ලයක් zip(seq1, seq2)නැද්ද?
නික්ලස් මර්ට්ස්

IkNiklasMertsch ඔව් එය හරියටම එකම ප්‍රති .ලයක් ඇත. සිප් ක්‍රියාකාරිත්වය පෙනෙන්නේ කෙසේදැයි මම උදාහරණයක් ඉදිරිපත් කළෙමි
ව්ලැඩ් බෙස්ඩන්

2

උනුට්බුගේ පිළිතුර මත පදනම්ව , මම පයිතන් 3.6 හි zip()කාර්යයන්, පයිතන්ගේ enumerate()ක්‍රියාකාරිත්වය, අත්පොත කවුන්ටරයක් ​​භාවිතා කිරීම ( count()ශ්‍රිතය බලන්න ), දර්ශක ලැයිස්තුවක් භාවිතා කිරීම සහ විශේෂ අවස්ථා වලදී සමාන ලැයිස්තු දෙකක ක්‍රියාකාරීත්වය සංසන්දනය කර ඇත්තෙමි . ලැයිස්තු දෙකෙන් එකක මූලද්‍රව්‍ය (එක්කෝ fooහෝ bar) අනෙක් ලැයිස්තුව සුචිගත කිරීම සඳහා භාවිතා කළ හැකිය. පිළිවෙලින් නව ලැයිස්තුවක් මුද්‍රණය කිරීම හා නිර්මාණය කිරීම සඳහා ඔවුන්ගේ කාර්ය සාධනය විමර්ශනය කරන ලද්දේ timeit()පුනරාවර්තන ගණන 1000 ගුණයක් වූ ශ්‍රිතයෙනි. මෙම පරීක්ෂණ සිදු කිරීම සඳහා මා විසින් නිර්මාණය කරන ලද පයිතන් පිටපතක් පහත දැක්වේ. fooසහ barලැයිස්තු වල ප්‍රමාණයන් මූලද්‍රව්‍ය 10 සිට 1,000,000 දක්වා විය.

ප්රතිපල:

  1. මුද්‍රණ කටයුතු සඳහා:zip() +/- 5% ක නිරවද්‍යතා ඉවසීමක් සාධක කිරීමෙන් පසුව, සලකා බලන ලද සියලු ප්‍රවේශයන්ගේ ක්‍රියාකාරිත්වය ශ්‍රිතයට ආසන්න වශයෙන් සමාන බව නිරීක්ෂණය විය . ලැයිස්තු ප්‍රමාණය මූලද්‍රව්‍ය 100 ට වඩා කුඩා වූ විට ව්‍යතිරේකයක් සිදුවිය. එවැනි තත්වයක් තුළ, දර්ශක ලැයිස්තු ක්‍රමය zip()ශ්‍රිතයට වඩා තරමක් මන්දගාමී වූ අතර enumerate()ශ්‍රිතය ~ 9% වේගවත් විය. අනෙක් ක්‍රම මඟින් zip()ශ්‍රිතයට සමාන කාර්ය සාධනයක් ලබා දී ඇත.

    මුද්‍රණ ලූප 1000 නියෝජිතයින්

  2. ලැයිස්තු නිර්මාණය කිරීම සඳහා: ලැයිස්තු නිර්මාණය කිරීමේ ප්‍රවේශයන් වර්ග දෙකක් ගවේෂණය කරන ලදී: (අ) list.append()ක්‍රමය සහ (ආ) ලැයිස්තු අවබෝධය භාවිතා කිරීම . +/- 5% ක නිරවද්‍යතාව ඉවසීමෙන් පසුව, මෙම ප්‍රවේශයන් දෙකටම, zip()ශ්‍රිතය enumerate()ලැයිස්තු දර්ශකයක් භාවිතා කිරීමට වඩා, අතින් කවුන්ටරයක් ​​භාවිතා කිරීමට වඩා ශ්‍රිතයට වඩා වේගයෙන් ක්‍රියාත්මක වන බව සොයා ගන්නා ලදී . zip()මෙම සංසන්දනයන්හි ක්‍රියාකාරීත්වයේ කාර්ය සාධනය 5% සිට 60% දක්වා වේගවත් විය හැකිය. සිත්ගන්නා කරුණ නම්, fooදර්ශකයේ මූලද්‍රව්‍යය භාවිතා කිරීමෙන් ශ්‍රිතයට barවඩා සමාන හෝ වේගවත් කාර්ය සාධනයක් (5% සිට 20% දක්වා) ලබා ගත හැකිය zip().

    ලැයිස්තුවක් නිර්මාණය කිරීම - 1000reps

මෙම ප්‍රති results ල පිළිබඳ හැඟීමක් ඇති කිරීම:

ක්‍රමලේඛකයෙකුට අර්ථවත් හෝ වැදගත්කමක් ඇති එක් මෙහෙයුමකට ගණනය කිරීමේ කාලය තීරණය කළ යුතුය.

උදාහරණයක් ලෙස, මුද්‍රණ කටයුතු සඳහා, මෙම කාල නිර්ණායකය තත්පර 1 ක් නම්, එනම් තත්පර 10 ** 0 නම්, තත්පර 1 ට වම්පස ඇති ප්‍රස්ථාරයේ y- අක්ෂය දෙස බලා එය මොනොමියල් වක්‍රය කරා ළඟා වන තෙක් තිරස් අතට ප්‍රක්ෂේපණය කරන්න. , මූලද්‍රව්‍ය 144 ට වඩා වැඩි ලැයිස්තු ප්‍රමාණ මඟින් ක්‍රමලේඛකයාට සැලකිය යුතු ගණනය කිරීමේ පිරිවැයක් සහ වැදගත්කමක් ඇති බව අපට පෙනේ. එනම්, කුඩා ලැයිස්තු ප්‍රමාණ සඳහා මෙම විමර්ශනයේ සඳහන් ප්‍රවේශයන් මගින් ලබා ගන්නා ඕනෑම කාර්ය සාධනයක් ක්‍රමලේඛකයාට වැදගත් නොවේ. ක්‍රමලේඛකයා නිගමනය කරනුයේ zip()මුද්‍රණ ප්‍රකාශ නැවත ප්‍රකාශ කිරීම සඳහා ශ්‍රිතයේ ක්‍රියාකාරිත්වය අනෙක් ප්‍රවේශයන්ට සමාන බවයි.

නිගමනය

නිර්මාණය zip()කිරීමේදී සමාන්තරව ලැයිස්තු දෙකක් හරහා ක්‍රියාකාරීත්වය භාවිතා කිරීමෙන් සැලකිය යුතු කාර්ය සාධනයක් ලබා ගත හැකිය list. ලැයිස්තු දෙකේ මූලද්‍රව්‍ය මුද්‍රණය කිරීම සඳහා සමාන්තරව ලැයිස්තු දෙකක් හරහා නැවත ක්‍රියා කරන විට, zip()ශ්‍රිතය ශ්‍රිතයට සමාන කාර්ය සාධනයක් ලබා දෙනු ඇත enumerate(), අතින් ප්‍රතිවිරුද්ධ විචල්‍යයක් භාවිතා කිරීම, දර්ශක ලැයිස්තුවක් භාවිතා කිරීම සහ විශේෂ අවස්ථා වලදී එහිදී ලැයිස්තු දෙකෙන් එකක මූලද්‍රව්‍ය (එක්කෝ fooහෝ bar) අනෙක් ලැයිස්තුව සුචිගත කිරීම සඳහා භාවිතා කළ හැකිය.

ලැයිස්තු නිර්මාණය පිළිබඳව සොයා බැලීමට භාවිතා කළ පයිතන් 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()

ඔබගේ printපරීක්ෂණ වල මුද්‍රණය කිරීමෙන් සෑම විටම පාහේ ගතවේ . මුද්‍රණය මිල අධිකයි. ලැයිස්තු ගොඩනැගිල්ලට ද යම් පිරිවැයක් ඇත.
user2357112 මොනිකා

@ user2357112supportsMonica එකඟයි. මුද්‍රණය සඳහා, පුනරාවර්තන කාර්ය සාධනය තීරණය කරනු ලබන්නේ මන්දගාමී පද්ධති I / O මෙහෙයුම් මගිනි, එබැවින් zip()ශ්‍රිතයේ ක්‍රියාකාරිත්වය හෝ මා සලකා බැලූ වෙනත් ප්‍රවේශයන් කෙරෙහි සංවේදී නොවේ .
සන් බෙයාර්

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

-1

යමෙකු මේ වගේ දෙයක් සොයන්නේ නම්, මම එය ඉතා සරල හා පහසු බව සොයා ගතිමි:

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

සිප් () මෙන් නොව ලැයිස්තු ඒවායේ සම්පූර්ණ අන්තර්ගතය සමඟ නැවත සැකසෙනු ඇත, එය අවම අන්තර්ගත දිග දක්වා පමණක් පුනරාවර්තනය වේ.


මගේ ප්‍රවේශයේ වැරැද්දක් සිදුවී ඇත්ද යන්න හෝ මෙම ප්‍රශ්නයට හැකි විසඳුමක් ලෙස එය නොගැලපේ නම් පහත සඳහන් අය අදහස් දැක්විය යුතුය.
VladiC4T

ඔව්, ඔවුන් පහත් කොට සලකන්නේ ඇයිදැයි මම නොදනිමි, මම මෙය ඉහළට ඔසවා තබමි;)
ස්පන්දනය 9

ප්‍රශ්න අසන්නාට අවශ්‍ය වන්නේ එකවර ලැයිස්තු ලැයිස්තු ගත කිරීමට හැකි වීමයි.
අම්ර් අල්හෝසරි

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.