如何解压缩迭代器?

时间:2015-06-12 14:03:04

标签: python iterator generator itertools

给定一对xys的列表,将其解压缩为两个列表的Python习语是:

xs, ys = zip(*xys)

如果xys是迭代器,我如何将其解压缩为两个迭代器,而不将所有内容存储在内存中?

3 个答案:

答案 0 :(得分:9)

假设您有一些可迭代的对:

a = zip(range(10), range(10))

如果我正确地解释了你的要求,你可以使用itertools.tee为第一和第二代生成独立的迭代器:

 xs, ys = itertools.tee(a)
 xs, ys = (x[0] for x in xs), (y[1] for y in ys)

注意这将在内存中保留您将其中一个与另一个进行迭代的“差异”。

答案 1 :(得分:6)

如果你想独立于另一个使用一个迭代器,那么就没有办法避免将内容拉入内存,因为其中一个迭代器会进行而另一个迭代器不会进行(因此必须缓冲)。 / p>

这样的东西允许你迭代左边的项目'和正确的项目'对:

 import itertools
 import operator

 it1, it2 = itertools.tee(xys)
 xs = map(operator.itemgetter(0), it1))
 ys = map(operator.itemgetter(1), it2))

 print(next(xs))
 print(next(ys))

...但请记住,如果只使用一个迭代器,另一个将缓冲内存中的项目,直到开始使用它们为止。

(顺便说一下,假设Python 3.在Python 2中,您需要使用itertools.imap(),而不是map()。)

答案 2 :(得分:0)

完整答案位于here。长话短说:我们可以为itertools.tee function修改Python配方,例如

from collections import deque


def unzip(iterable):
    """
    Transposes given iterable of finite iterables.
    """
    iterator = iter(iterable)
    try:
        first_elements = next(iterator)
    except StopIteration:
        return ()
    queues = [deque([element])
              for element in first_elements]

    def coordinate(queue):
        while True:
            if not queue:
                try:
                    elements = next(iterator)
                except StopIteration:
                    return
                for sub_queue, element in zip(queues, elements):
                    sub_queue.append(element)
            yield queue.popleft()

    return tuple(map(coordinate, queues))

然后使用它

>>> from itertools import count
>>> zipped = zip(count(), count())
>>> xs, ys = unzip(zipped)
>>> next(xs)
0