Looping in Parallel over Index and Sequence Items
Credit: Alex Martelli
Problem
You need to loop on a sequence, but at each step you also need to know what index into the sequence you have reached.
Solution
Together, the built-in functions
xrange
and zip make this easy. You need only this one
instance of xrange, as it is fully reusable:
indices = xrange(sys.maxint)
Here’s how you use the indices
instance:
for item, index in zip(sequence, indices):
something(item, index)This gives the same semantics as:
for index in range(len(sequence)):
something(sequence[index], index)but the change of emphasis allows greater clarity in many usage contexts.
Another alternative is to use class wrappers:
class Indexed:
def _ _init_ _(self, seq):
self.seq = seq
def _ _getitem_ _(self, i):
return self.seq[i], iFor example:
for item, index in Indexed(sequence):
something(item, index)In Python 2.2, with from _ _future_ _ import generators, you can also use:
def Indexed(sequence):
iterator = iter(sequence)
for index in indices:
yield iterator.next( ), index
# Note that we exit by propagating StopIteration when .next raises it!However, the simplest roughly equivalent way remains the good old:
def Indexed(sequence):
return zip(sequence, indices)Discussion
We often want to loop on a sequence but also need the current index in the loop body. The canonical Pydiom for this is:
for i in range(len(sequence)):
using sequence[i] as the item reference in the loop’s body. However, in many contexts, it is clearer to emphasize ...