Source code for bronx.syntax.iterators

# -*- coding: utf-8 -*-

"""
Useful iterators and associated tools..
"""

from __future__ import print_function, absolute_import, unicode_literals, division

from collections import deque


[docs]def pcn(iterable, fillvalue=None): """Iterate over **iterable** but also return the previous and next values. Example:: >>> for p, c, n in pcn([]): ... print(p, c, n) >>> for p, c, n in pcn([1, ]): ... print(p, c, n) None 1 None >>> for p, c, n in pcn([1, 2, 3, 4, 5]): ... print(p, c, n) None 1 2 1 2 3 2 3 4 3 4 5 4 5 None >>> for p, c, n in pcn([1, 2, None, 4, 5], fillvalue='foo'): ... print(p, c, n) foo 1 2 1 2 None 2 None 4 None 4 5 4 5 foo """ iterator = iter(iterable) sentinel = object() def _stransform(result): return fillvalue if result is sentinel else result prev = deque([sentinel, sentinel], maxlen=2) try: prev.append(next(iterator)) while True: cur = next(iterator) yield _stransform(prev[0]), prev[-1], cur prev.append(cur) except StopIteration: if prev[-1] is not sentinel: yield _stransform(prev[0]), prev[-1], fillvalue return
[docs]def izip_pcn(* iterables): """Like izip but also returns the Previous, Current and Next values. Example:: >>> for p, c, n in izip_pcn([], []): ... print(p, c, n) >>> for p, c, n in izip_pcn([1, ], [10, ]): ... print(p, c, n) (None, None) (1, 10) (None, None) >>> for p, c, n in izip_pcn([1, 2], [10, 11]): ... print(p, c, n) (None, None) (1, 10) (2, 11) (1, 10) (2, 11) (None, None) >>> for p, c, n in izip_pcn([1, 2, 3, 4], [10, 11, None, 13]): ... print(p, c, n) (None, None) (1, 10) (2, 11) (1, 10) (2, 11) (3, None) (2, 11) (3, None) (4, 13) (3, None) (4, 13) (None, None) """ iterators = [pcn(i) for i in iterables] try: while iterators: currents = [next(i) for i in iterators] yield [tuple([c[i] for c in currents]) for i in (0, 1, 2)] except StopIteration: return
[docs]def interleave(* iterables): """Take several iterable objects and iterate in a roundrobin manner. Example:: >>> print(','.join( ... interleave('abcd', '1234', 'ABCD') ... )) a,1,A,b,2,B,c,3,C,d,4,D >>> print(','.join( ... interleave('abcd', '12', 'ABCD') ... )) a,1,A,b,2,B,c,C,d,D >>> print(','.join( ... interleave('ab', '1234', 'ABCD') ... )) a,1,A,b,2,B,3,C,4,D """ my_iterators = [iter(it) for it in iterables] my_index = len(iterables) - 1 while True: found = None my_index += 1 while my_iterators and found is None: my_index %= len(my_iterators) try: found = next(my_iterators[my_index]) except StopIteration: del my_iterators[my_index] if found is None: return else: yield found
if __name__ == '__main__': import doctest doctest.testmod()