簡體   English   中英

將一對發電機轉變為一對發電機

[英]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)

這里有一個根本問題。 假設您獲得了兩個迭代器iter1iter2 ,並將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將只是zipimap只是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))

您可以直接使用gen1gen2

案例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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM