# itertools.izip brokeness

rurpy at yahoo.com rurpy at yahoo.com
Fri Jan 6 02:13:13 EST 2006

```"Michael Spencer" <mahs at telcopartners.com> wrote in message
news:mailman.107.1136516348.27775.python-list at python.org...
>
> > Bengt Richter wrote:
> ...
> >>  >>> from itertools import repeat, chain, izip
> >>  >>> it = iter(lambda z=izip(chain([3,5,8],repeat("Bye")), chain([11,22],repeat("Bye"))):z.next(), ("Bye","Bye"))
> >>  >>> for t in it: print t
> >>  ...
> >>  (3, 11)
> >>  (5, 22)
> >>  (8, 'Bye')
> >>
> >> (Feel free to generalize ;-)
> >
>
> rurpy at yahoo.com wrote:
> > Is the above code as obvious as
> >   izip([3,5,8],[11,22],sentinal='Bye')?
> > (where the sentinal keyword causes izip to iterate
> > to the longest argument.)
> >
>
>
> from itertools import repeat
>
> def izip2(*iterables, **kw):
>      """kw:fill. An element that will pad the shorter iterable"""
>      fill = repeat(kw.get("fill"))
>      iterables = map(iter, iterables)
>      iters = range(len(iterables))
>
>      for i in range(10):
>          result = []
>          for idx in iters:
>              try:
>                  result.append(iterables[idx].next())
>              except StopIteration:
>                  iterables[idx] = fill
>                  if iterables.count(fill) == len(iterables):
>                      raise
>                  result.append(fill.next())
>          yield tuple(result)
>
>   >>> list(izip2(range(5), range(3), range(8), range(2)))
>   [(0, 0, 0, 0), (1, 1, 1, 1), (2, 2, 2, None), (3, None, 3, None), (4, None, 4,
> None), (None, None, 5, None), (None, None, 6, None), (None, None, 7, None)]
>   >>> list(izip2(range(5), range(3), range(8), range(2), fill="Empty"))
>   [(0, 0, 0, 0), (1, 1, 1, 1), (2, 2, 2, 'Empty'), (3, 'Empty', 3, 'Empty'), (4,
> 'Empty', 4, 'Empty'), ('Empty', 'Empty', 5, 'Empty'), ('Empty', 'Empty', 6,
> 'Empty'), ('Empty', 'Empty', 7, 'Empty')]
>   >>>

This may be getting too kludgey but by counting the
exhausted iterators you can allow for arguments
containing infinite iterators:

def izip4(*iterables, **kw):
"""kw:fill. An element that will pad the shorter iterable
kw:infinite. Number of non-terminating iterators """
fill = repeat(kw.get("fill"))
iterables = map(iter, iterables)
iters = range(len(iterables))
finite_cnt = len(iterables) - kw.get("infinite", 0)

while True:
result = []
for idx in iters:
try:
result.append(iterables[idx].next())
except StopIteration:
iterables[idx] = fill
finite_cnt -= 1
if finite_cnt == 0:
raise
result.append(fill.next())
yield tuple(result)

>>> print list(izip4(range(5), range(3), range(8), range(2), fill='empty'))
[(0, 0, 0, 0), (1, 1, 1, 1), (2, 2, 2, 'empty'), (3, 'empty', 3,
'empty'),
(4, 'empty', 4, 'empty'), ('empty', 'empty', 5, 'empty'),
('empty', 'empty', 6, 'empty'), ('empty', 'empty', 7, 'empty')]

>>> print list(izip4(range(5), repeat('foo'), range(8), count(), infinite=2, fill='empty'))
[(0, 'foo', 0, 0), (1, 'foo', 1, 1), (2, 'foo', 2, 2), (3, 'foo', 3,
3), (4, 'foo', 4, 4),
('empty', 'foo', 5, 5), ('empty', 'foo', 6, 6), ('empty', 'foo', 7, 7)]

```