给定一对xys
的列表,将其解压缩为两个列表的Python习语是:
xs, ys = zip(*xys)
如果xys
是迭代器,我如何将其解压缩为两个迭代器,而不将所有内容存储在内存中?
答案 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