Iterating through two lists

Robert Amesz sheershion at mailexpire.com
Sat May 25 20:08:16 EDT 2002


Boudewijn Rempt wrote:

> jb wrote:
> 
>> I have two lists, x and y with the property len(x) = len(y).
>> 
>> I should like to achive this (x is a list of class instances)
>> 
>>   for (a,b) in (x,y): a.f(b)
>> 
>> Is there a fancy way of doing this or have I to introduce an
>> auxillary counter (that is very easy but maybe not very "lispy",
>> that is "python-like"). 
>> 
> 
> Is this what you want?
> 
>>>> a=[1,2,3]
>>>> b=['a','b','c']
>>>> map(None, a, b)
> [(1, 'a'), (2, 'b'), (3, 'c')]
>>>> for t in map(None, a, b):
> ...     print t
> ...
> (1, 'a')
> (2, 'b')
> (3, 'c')
>>>> for i, j in map(None, a, b):
> ...     print i, j
> ...
> 1 a
> 2 b
> 3 c

With Python 2.2, you'd expect to be able do things like that with some 
iterator magic, but oddly enough I couldn't find anything. No matter, I 
can do that myself:

--- cut ---

class paralleliter:
    def __init__(self, *sequences):
        if not sequences:
            raise ValueError("Nothing to iterate over")
        self.iterators = map(iter, sequences)

    def __iter__(self):
        return self

    def next(self):
        return [x.next() for x in self.iterators]


l1 = [1, 2, 3]
l2 = ['a', 'b', 'c']


for r in paralleliter(l1, l2):
    print r

--- cut ---

This results in:

[1, 'a'][2, 'b'][3, 'c']

You might argue that paralleliter should raise an exception when 
sequences are of unequal length. Well, this isn't terribly hard to 
implement, even though you _cannot_ use len() to test this, because 
iterators have no predetermined length. However, the code loses a lot 
of its elegance this way:


--- cut ---

class paralleliter2:
    def __init__(self, *sequences):
        if not sequences:
            raise ValueError("Nothing to iterate over")
        self.iterators = map(iter, sequences)

    def __iter__(self):
        return self

    def next(self):
        result = []
        for x in self.iterators:
            try:
                result.append(x.next())
            except StopIteration:
                pass
        if len(result) == 0:
            raise StopIteration
        if len(result) <> len(self.iterators):
            raise ValueError("Sequences are of unequal length")
        return result


--- cut ---

Personally, I'd like this type of parallel iterator (and perhaps a 
serial one, too) to be added to the set of builtin functions: this type 
of iteration comes up time and time again in this newsgroup, and it 
would be nice to have a universal and canonical way to settle it once 
and for all.


Robert Amesz



More information about the Python-list mailing list