我如何转换成对的生成器(元组):
tuple_gen = (i for i in [(1, "a"), (2, "b"), (3, "c")])
分成两个生成[1, 2, 3]
和["a", "b", "c"]
?
我需要单独处理元组的第一个和第二个元素,处理函数需要迭代。
生成器非常大(数百万项),所以除非没有其他解决方案,否则我希望避免同时将所有项目都存储在内存中。
答案 0 :(得分:1)
您可以使用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)
答案 1 :(得分:1)
这里存在根本问题。假设您获得了两个迭代器iter1
和iter2
,并将iter1
传递给了一个吃掉整个事物的函数:
def consume(iterable):
for thing in iterable:
do_stuff_with(thing)
consume(iter1)
那将需要遍历所有tuple_gen
来获取第一项,然后你对第二项做什么?除非您重新运行生成器以再次获取第二个项目,否则您需要将所有这些项目存储在内存中,除非您可以将它们保存到磁盘或其他内容中,因此您不会比将它们保存到更好的状态。您只需将tuple_gen
转储到列表中。
如果这样做,你必须并行使用迭代器,或者运行底层生成器两次,或者花费大量内存来保存你不处理的元组元素,以便其他迭代器可以覆盖它们。遗憾的是,并行使用迭代器将需要重写消费者函数或在单独的线程中运行它们。如果可以的话,运行两次发生器是最简单的,但并不总是一个选项。
答案 2 :(得分:0)
您可以使用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
答案 3 :(得分:-1)
案例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)
我认为没有办法将生成器,迭代器重置到第一个位置。