indexed looping, functional replacement?

Alex Martelli aleax at aleax.it
Sun Nov 10 05:34:50 EST 2002


Bengt Richter wrote:
    ...
> also a lazy zip, to avoid building lists you don't use (untested beyond
> what you see ;-)
> 
>  >>> from __future__ import generators
>  >>> def xzip(*args):
>  ...     for i in xrange(min(map(len,args))):
>  ...         yield tuple([x[i] for x in args])
>  ...
>  >>> for f,s in xzip(fl,sl):
>  ...     f(s)
>  ...
>  f1: bbb
>  f2: sdf
>  f3: sdw

I think that xzip can be simplified a bit -- as code, the for
statement is threateningly complex, and the tupleization of the
yielded sublists just a bit of conceptual and runtime overhead,
for most practical purposes.  So, I might code it, instead:

def xzip(*args):
    iters = map(iter, args)
    while True:
        yield [x.next() for x in iters]

the key idea here is that the first iterator to run out will
let the fact be known by raising StopIteration, and xzip just
lets that exception propagate, thus in turn letting its caller
know that xzip has also run out of items to iterate on.


Of course, the semantics are slightly different.  The original
xzip needs arguments that are sequences (i.e., can be passed to
'len', and indexed by integers 0 and up), while this simpler one
accepts arguments that are iterable (can be subjected to iter).
All sequences are iterable, but not vice versa (file objects open
for reading, for example, are iterable, but not sequences).

So, for example, this simpler xzip could be used to print out
a textfile's lines with numbering:

for line, linenumber in xzip(open('the.txt'), xrange(sys.maxint)):
    print '%d: %s' % (linenumber, line),

while the original would die with a TypeError if used in this
way (the file object can be iterated on, but not indexed, nor
can it be passed as the argument to built-in 'len').  However,
it seems to me that the simpler xzip's greater generality is
not a substantial problem -- simplicity IS nice to have.


Alex




More information about the Python-list mailing list