can list comprehensions replace map?

Andrew Dalke dalke at dalkescientific.com
Thu Jul 28 03:05:58 EDT 2005


Steven Bethard wrote:
> Here's one possible solution:
> 
> py> import itertools as it
> py> def zipfill(*lists):
> ... 	max_len = max(len(lst) for lst in lists)

A limitation to this is the need to iterate over the
lists twice, which might not be possible if one of them
is a file iterator.

Here's a clever, though not (in my opinion) elegant solution

import itertools

def zipfill(*seqs):
    count = [len(seqs)]
    def _forever(seq):
        for item in seq: yield item
        count[0] -= 1
        while 1: yield None
    seqs = [_forever(seq) for seq in seqs]
    while 1:
        x = [seq.next() for seq in seqs]
        if count == [0]:
            break
        yield x

for x in zipfill("This", "is", "only", "a", "test."):
    print x

This generates

['T', 'i', 'o', 'a', 't']
['h', 's', 'n', None, 'e']
['i', None, 'l', None, 's']
['s', None, 'y', None, 't']
[None, None, None, None, '.']

This seems a bit more elegant, though the "replace" dictionary is
still a bit of a hack

from itertools import repeat, chain, izip

sentinel = object()
end_of_stream = repeat(sentinel)

def zipfill(*seqs):
    replace = {sentinel: None}.get
    seqs = [chain(seq, end_of_stream) for seq in seqs]
    for term in izip(*seqs):
        for element in term:
            if element is not sentinel:
                break
        else:
            # All sentinels
            break
            
        yield [replace(element, element) for element in term]


(I originally had a "element == tuple([sentinel]*len(seqs))" check
but didn't like all the == tests incurred.)

				Andrew
				dalke at dalkescientific.com




More information about the Python-list mailing list