Welcome, guest | Sign In | My Account | Store | Cart

Often you need to loop through every item of multiple lists and compare them. This can be done without a using a counter.

Python, 21 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
a = ['a1', 'a2', 'a3']
b = ['b1', 'b2']

# will iterate 3 times,
# the last iteration, b will be None
print "Map:"
for x, y in map(None, a, b):
  print x, y

# will iterate 2 times,
# the third value of a will not be used
print "Zip:"
for x, y in zip(a, b):
  print x, y

# will iterate 6 times,
# it will iterate over each b, for each a
# producing a slightly different outpu
print "List:"
for x, y in [(x,y) for x in a for y in b]:
    print x, y

Using map with "None" as the first argument is discussed in the docs:

"If function is None, the identity function is assumed; if there are multiple list arguments, map() returns a list consisting of tuples containing the corresponding items from all lists (i.e. a kind of transpose operation). The list arguments may be any kind of sequence; the result is always a list."

Note: this returns None for sequences where there is no element. Output:<pre>a1 b1 a2 b2 a3 None</pre>

Zip allows you to iterate over the lists in a similar way, but only up to the number of elements of the smallest list.

Output:<pre>a1 b1 a2 b2</pre>

Python 2.0 introduced list comprehension which explains the rather strange syntax: <pre>[(x,y) for x in a for y in b]</pre> this iterates over the b list for every element in a. These are put into a tuple x, y. We then iterate through that tuple in the outermost for loop.

The result is quite different:<pre>a1 b1 a1 b2 a2 b1 a2 b2 a3 b1 a3 b2</pre>

3 comments

Hamish Lawson 20 years, 7 months ago  # | flag

Mention zip for shortest list? You may want to mention that zip(a, b) could be used where you wanted the shortest list to determine how many cross-sections were taken, rather than the longest list as with map.

andy mckay (author) 20 years, 7 months ago  # | flag

Good idea. Mentioned...

Corey Coughlin 18 years, 12 months ago  # | flag

loop unrolling.

Nice tip, I wish I had found this site sooner.  I had a similar
problem with loops, in that I found myself with lots of code that
looks like this:

for a in x:
    for b in y:
        for c in z:
            .......

I kept getting tabbed over so far it was getting annoying, so I wrote
a little function, permuteflat(), so I could do this:

for a, b, c in permuteflat(x,y,z):

which seems to work pretty well.  I hadn't heard about the 'for a in x
for b in y' syntax then, though.  But for laughs, here's permuteflat:

def permuteflat(*args):
    outs = []
    olen = 1
    tlen = len(args)
    for seq in args:
        olen = olen * len(seq)
    for i in range(olen):
        outs.append([None] * tlen)
    plq = olen
    for i in range(len(args)):
        seq = args[i]
        plq = plq / len(seq)
        for j in range(olen):
            si = (j / plq) % len(seq)
            outs[j][i] = seq[si]
    for i in range(olen):
        outs[i] = tuple(outs[i])
    return outs

I probably could have done this much more easily recursively, or any
other way, really, but I was working on truth tables at the time and
it seemed like the obvious way to go.  Thanks again for the tip!
Created by andy mckay on Thu, 21 Jun 2001 (PSF)
Python recipes (4591)
andy mckay's recipes (8)
Python Cookbook Edition 2 (117)
Python Cookbook Edition 1 (103)

Required Modules

  • (none specified)

Other Information and Tasks