如何存储itertools.chain并多次使用它?

10

我希望使用 itertools.chain 来高效地连接列表(记忆化),但我需要能够多次读取(或使用 map 等方法)结果。以下是一个例子,说明了这个问题:

import itertools
a = itertools.chain([1, 2], [3, 4])
print list(a) # => [1, 2, 3, 4]
print list(a) # => []

如何最好地避免这个问题?

2个回答

14

与所有生成器一样,您需要将其转换为列表并存储该结果:

a = list(a)

这是生成器的一个基本原则,它们只能产生其序列一次

此外,您不能仅仅为了记忆化而存储生成器,因为底层列表可能会发生变化。在几乎所有记忆化用例中,您应该存储列表;生成器通常仅用于高效地转换或过滤底层序列,并不代表您想要记忆化的数据本身。 这就像存储函数而不是其输出一样。对于您的特定情况,如果您所做的一切都是使用chain()来连接现有列表,请直接存储这些列表

请注意,这使生成器能够生成无限序列,因此要小心将其转换为列表。


谢谢提供信息。听起来我应该只需连接这些列表。有比 list1 + list2 + ... 更高效的方法吗? - jtbandes
@jtbandes:你可以使用 timeit 来比较 list(chain())list1 + ..,但我猜测后者会更有效率。 - Martijn Pieters

4

尝试使用 itertools.tee

import itertools
a = itertools.chain([1, 2], [3, 4])
a, b = itertools.tee(a)
print list(b) # => [1, 2, 3, 4]
a, b = itertools.tee(a)
print list(b) # => [1, 2, 3, 4]

这并不改变记忆化生成器是无用的事实。 - Martijn Pieters
4
从文档中得知:通常情况下,如果一个迭代器在另一个迭代器开始之前使用了大部分或全部数据,则使用list()比使用tee()更快。 - Paolo Moretti
3
请注意,海报并没有询问哪个更快或更好,他们的问题是如何重复使用生成器,而itertools.tee恰好提供了这种功能。 - georg
2
@thg435 我的评论更像是一个注释,给那些可能遇到这个问题的人提醒。 - Paolo Moretti

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接