[Tutor] len(l) as loop index

Kirby Urner urnerk@qwest.net
Thu, 04 Apr 2002 07:26:06 -0800


At 07:46 AM 4/4/2002 -0600, Christopher Smith wrote:

>The first method has been the method of choice for the
>How to Think text on Python for beginners.
>
>/c

I'd say all of the above loop forms are fine.  The
"incremented index in order to access a list" approach
is very typical of many computer languages.

However, the 'for element in iter-sequence' construct
means that in Python we're less likely to compute an
incrementing index for the mere purpose of accessing
each element in turn, so it's important to show, and
use, this freedom.

Sometimes when I think I need an index, e.g. to access
both an element and the next element after, in the
same expression, I can actually do without.

For example,

 >>> def edges(face):
         lenface = len(face)
         edges = []
         for i in range(lenface):
            if i+1 < lenface:
               edges.append((face[i], face[i+1]))
            else:
               edges.append((face[i], face[0]))
        return edges

 >>> edges(['A','C','D','E'])
[('A', 'C'), ('C', 'D'), ('D', 'E'), ('E', 'A')]

This program takes a polyhedron's face and figures
out what edges it implies, i.e. given face ACDE, you
must have edges AC CD DE and EA.  At first blush,
I need indexed access to the face in order to get
the pair (face[i],face[i+1]) -- except at the end
I have to "wrap around" to the beginning.

However, more recently, I've taken to writing this
function this way:

 >>> def edges(face):
         return zip(face,face[1:]+[face[0]])

 >>> edges(['A','C','D','E'])
[('A', 'C'), ('C', 'D'), ('D', 'E'), ('E', 'A')]

except I really want sorted edges, i.e. ('A','E')
not ('E','A') -- because this makes it easier to
purge duplicates, I don't need to worry that
two edges might be the same except for the order
of the vertices, given I force the order.

So, final form:

def sort(thelist):  # called from various functions
         thelist.sort()
         return thelist

def edges(face):
         edges = []
         for i,j in zip(face,face[1:]+[face[0]]):
            edges.append(sort(list((i,j))))
         return edges

 >>> edges(['A','C','D','E'])
[['A', 'C'], ['C', 'D'], ['D', 'E'], ['A', 'E']]

There would be other forms of the above, but the main
point here is that I don't need to use indexing
syntax in the body of the loop -- just once in the
for statement to construct a "wrapped list" i.e.
['A','B','C','D'] becomes ['B','C','D','A'] and,
when zipped with the unwrapped list, you get the
edge pairs you need right off the bat.  All that
remains is to do the sort.

Kirby