Source code for chainercv.utils.iterator.unzip

import collections


class BufferedIterator(object):
    """Buffered iterator for :func:`unzip`.

    This iterator contains :obj:`buffers` and :obj:`index`.
    The buffers are shared with other :class:`BufferedIterator`s.
    When :method:`__next__` or :method:`next` is called,
    this iterator checks :obj:`buffers[index]` fisrt.
    If :obj:`buffers[index]` has some values, it pops
    the first value and returns it. Otherwise, it gets
    a new tuple from the base iterator and pushes the values
    into :obj:`buffers`.

    When this iterator is deleted, it disables the corresponding buffer
    by setting :obj:`buffers[index]` to :obj:`None`.
    With this mark, other iterators can skip values for this deleted
    iterator and memory usage can be reduced.

    Args:
        iterator (iterator): A base iterator of tuples. All tuples should have
            the same length.
        buffers (list of collections.deque): A list of
            :class:`collections.deque` to buffer values.
            The size of this list should be same as those of tuples
            from :obj:`iterator`.
        index (int): The index of this :class:`BufferedIterator`.

    """

    def __init__(self, iterator, buffers, index):
        self.iterator = iterator
        self.buffers = buffers
        self.index = index

    def __del__(self):
        self.buffers[self.index] = None

    def __iter__(self):
        return self

    def __next__(self):
        try:
            return self.buffers[self.index].popleft()
        except IndexError:
            values = next(self.iterator)
            for buf, val in zip(self.buffers, values):
                # skip a value if the correponding iterator is deleted.
                if buf is not None:
                    buf.append(val)
            return self.buffers[self.index].popleft()

    next = __next__


[docs]def unzip(iterable): """Converts an iterable of tuples into a tuple of iterators. This function converts an iterable of tuples into a tuple of iterators. This is an inverse function of :func:`six.moves.zip`. >>> from chainercv.utils import unzip >>> data = [(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd'), (4, 'e')] >>> int_iter, str_iter = unzip(data) >>> >>> next(int_iter) # 0 >>> next(int_iter) # 1 >>> next(int_iter) # 2 >>> >>> next(str_iter) # 'a' >>> next(str_iter) # 'b' >>> next(str_iter) # 'c' Args: iterable (iterable): An iterable of tuples. All tuples should have the same length. Returns: tuple of iterators: Each iterator corresponds to each element of input tuple. Note that each iterator stores values until they are popped. To reduce memory usage, it is recommended to delete unused iterators. """ iterator = iter(iterable) values = next(iterator) buffers = [collections.deque((val,)) for val in values] return tuple( BufferedIterator(iterator, buffers, index) for index in range(len(buffers)))