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 22 years, 10 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) 22 years, 10 months ago  # | flag

Good idea. Mentioned...

Corey Coughlin 21 years, 3 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