Categories
for-loop iterator list python

How do I iterate through two lists in parallel?

1151

I have two iterables, and I want to go over them in pairs:

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

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

That should result in:

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

One way to do it is to iterate over the indices:

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

But that seems somewhat unpythonic to me. Is there a better way to do it?

0

    1795

    Python 3

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

    zip stops when the shorter of foo or bar stops.

    In Python 3, zip
    returns an iterator of tuples, like itertools.izip in Python2. To get a list
    of tuples, use list(zip(foo, bar)). And to zip until both iterators are
    exhausted, you would use
    itertools.zip_longest.

    Python 2

    In Python 2, zip
    returns a list of tuples. This is fine when foo and bar are not massive. If they are both massive then forming zip(foo,bar) is an unnecessarily massive
    temporary variable, and should be replaced by itertools.izip or
    itertools.izip_longest, which returns an iterator instead of a list.

    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 stops when either foo or bar is exhausted.
    izip_longest stops when both foo and bar are exhausted.
    When the shorter iterator(s) are exhausted, izip_longest yields a tuple with None in the position corresponding to that iterator. You can also set a different fillvalue besides None if you wish. See here for the full story.


    Note also that zip and its zip-like brethen can accept an arbitrary number of iterables as arguments. For example,

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

    prints

    1 red manchego
    2 blue stilton
    3 green brie
    

    12

    • @unutbu Why would I prefer OP’s method over the izip one (even though the izip/ zip looks much cleaner)?

      – armundle

      Mar 14, 2016 at 19:23

    • 3

      You might want to mention Python 3 first, as it’s probably more future-proof. Moreover, it*s worth pointing out that in Python 3, zip() has exactly that advantage that only itertools.izip() had in Python 2 and thus it is usually the way to go.

      – Daniel S.

      Jun 14, 2016 at 17:40

    • 5

      May I ask you to update your answer to explicitly state that zip and zip-like functions from itertools accept any number of iterables and not just 2? This question is canonical now and your answer is the only one worth updating.

      – vaultah

      Jul 11, 2016 at 15:01

    • what if additionally I want the index i? Can I wrap that zip in enumerate?

      Mar 6, 2018 at 18:05

    • 2

      @CharlieParker: Yes you can, but then you would use for i, (f, b) in enumerate(zip(foo, bar)).

      – unutbu

      Mar 6, 2018 at 19:20

    84

    You want the zip function.

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

    1

    • 13

      Before Python 3.0 you’d want to use itertools.izip if you have large numbers of elements.

      Nov 2, 2009 at 21:35

    21

    You should use ‘zip‘ function. Here is an example how your own zip function can look like

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

    3

    • 1

      Doesn’t this have exactly the same result as zip(seq1, seq2)?

      Jun 6, 2018 at 9:35

    • 1

      @NiklasMertsch yes it has exactly the same result. I just provided example how zip function looks like

      Jun 6, 2018 at 15:40

    • 1

      This is a pretty limited reinvention of zip and the wording is rather misleading. If you’re going to reinvent the wheel (don’t–it’s a builtin function, not a dependency), at least this answer accepts a variable number of iterables and generally behaves as you’d expect zip to.

      – ggorlen

      Feb 7, 2021 at 4:27