[英]Turning a generator of pairs into a pair of generators
我如何轉換成對的生成器(元組):
tuple_gen = (i for i in [(1, "a"), (2, "b"), (3, "c")])
進入兩個產生[1, 2, 3]
和["a", "b", "c"]
發生器?
我需要單獨處理元組的第一個和第二個元素,處理函數期望迭代。
生成器非常大(數百萬項)所以我想避免在內存中同時存在所有項目,除非沒有其他解決方案。
您可以使用itertools包中的tee函數創建n
不同的迭代器。 然后,您將分別迭代它們:
from itertools impor tee
i1, i2 = tee(tuple_gen, n=2)
firsts = (x[0] for x in i1)
seconds = (x[1] for x in i2)
這里有一個根本問題。 假設您獲得了兩個迭代器iter1
和iter2
,並將iter1
傳遞給一個吃掉整個事物的函數:
def consume(iterable):
for thing in iterable:
do_stuff_with(thing)
consume(iter1)
那將需要遍歷所有tuple_gen
來獲取第一個項目,然后你用第二個項目做什么? 除非您可以重新運行生成器以再次獲取第二個項目,否則您需要將所有這些項目存儲在內存中,除非您可以將它們保存到磁盤或其他內容中,因此您不會比僅僅更好地存儲它們。將tuple_gen
轉儲到列表中。
如果你這樣做,你必須並行使用迭代器,或者運行底層生成器兩次,或者花費大量內存來保存你沒有處理的元組元素,以便其他迭代器可以覆蓋它們。 遺憾的是,並行使用迭代器將需要重寫消費者函數或在單獨的線程中運行它們。 如果可以的話,運行兩次發生器最簡單,但並不總是一個選項。
您可以使用itertools
進行如下操作:
>>>from itertools import chain, izip, imap
>>>tuple_gen = (i for i in [(1, "a"), (2, "b"), (3, "c")])
>>>nums_gen, letters_gen = imap(lambda x: chain(x), izip(*tuple_gen))
>>>list(nums_gen)
[1, 2, 3]
>>>list(letters_gen)
['a', 'b', 'c']
注意 :
對於python3, izip
將只是zip
, imap
只是map
情況1
我不知道它來自哪里[(1, "a"), (2, "b"), (3, "c")]
但是如果它來自如下代碼
gen1 = (i for i in [1,2,3])
gen2 = (i for i in ["a", "b", "c"])
tuple_gen = (i for i in zip(gen1, gen2))
您可以直接使用gen1
和gen2
。
案例2
如果您已經創建了列表[(1, "a"), (2, "b"), (3, "c")]
並且只是不想創建列表兩次。 你可以在下面這樣做。
lst = [(1, "a"), (2, "b"), (3, "c")]
gen1 = (i[0] for i in lst)
gen2 = (i[1] for i in lst)
案例3
否則,只需創建一個列表,但它會占用CPU資源來擴展生成器。 這是你不想要的。
tuple_gen = (i for i in [(1, "a"), (2, "b"), (3, "c")])
tmp = list(tuple_gen)
gen1 = iter(tmp)
gen2 = iter(tmp)
我認為沒有辦法將發生器,迭代器重置到第一個位置。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.