Учитывая список пар xys
, идиома Python для распаковки его в два списка:
xs, ys = zip(*xys)
Если xys
- итератор, как я могу разархивировать его на два итератора, не сохраняя все в памяти?
Учитывая список пар xys
, идиома Python для распаковки его в два списка:
xs, ys = zip(*xys)
Если xys
- итератор, как я могу разархивировать его на два итератора, не сохраняя все в памяти?
Предположим, что у вас есть несколько итераций пар:
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)
Примечание, это сохранит в памяти "разницу" между тем, сколько вы повторяете одно из них, и другое.
Если вы хотите потреблять один итератор независимо друг от друга, нет никакого способа избежать потащить материал в память, поскольку один из итераторов будет прогрессировать, пока другой не будет (и, следовательно, должен буферизировать).
Что-то вроде этого позволяет вам перебирать как "левые элементы", так и "правильные элементы" пар:
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))
... но имейте в виду, что если вы потребляете только один итератор, другой будет хранить элементы в памяти до тех пор, пока вы не начнете их употреблять.
(Btw, предполагая Python 3. В Python 2 вам нужно использовать itertools.imap()
, а не map()
.)
Полный ответ находится здесь. Короче говоря: мы можем изменить рецепт Python для функции itertools.tee
например:
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