我需要生成itertool.permutation
生成器列表的产品,并使用以下代码:
def iter_version():
l = [itertools.permutations(range(10)) for _ in range(10)]
g = itertools.product(*l)
for i in g:
yield i
但这段代码很慢。我的桌面需要16秒。除了告诉我这个功能需要16秒时,cProfile什么也没有显示。
如果我像这样创建一些疯狂的循环:
def for_loop():
l = [itertools.permutations(range(10)) for _ in range(10)]
for i0 in l[0]:
for i1 in l[1]:
for i2 in l[2]:
for i3 in l[3]:
for i4 in l[4]:
for i5 in l[5]:
for i6 in l[6]:
for i7 in l[7]:
for i8 in l[8]:
for i9 in l[9]:
yield (i0, i1, i2, i3, i4, i5, i6, i7, i8, i9)
这几乎是立即运行。
在我的情况下,排列生成器列表不是固定大小,所以我不能使用for循环版本。
答案 0 :(得分:1)
就像@ DSM的回答所说,itertools.product
会将迭代转换为具体的序列。这可以从http://bugs.python.org/issue10109
为了解决这个问题而不将iterable转换为list,我使用了这个函数。请注意,此函数使用递归,因此请在使用前进行测试。
def product(*args):
if len(args) == 1:
for i in args[0]:
yield [i]
else:
for i in args[0]:
for j in product(*args[1:]):
j.append(i)
yield j
答案 1 :(得分:0)
尊敬地说,我不相信你的第一个代码需要运行16秒。有(3628800)^ 10,或395940866122425193243875570782668457763038822400000000000000000000,要产生的元素。我可以想象它在一些系统上花了16秒来计算3628800 * 10 = 36288000的排列。 (由于你没有显示你如何调用iter_version
,你可能只是在next(iter_version())
之后,或者其他什么,我想,尽管如此,有更简单的方法来获取它......)
iter_version
和for_loop
之间的真正区别在于itertools.product
没有实现笛卡尔积,但 将每个参数转换为a首先列出,列表可以重复迭代。在for_loop
中,你正在耗费你的迭代器,所以你的工作几乎没有那么多。
使用较小的案例可能更容易看到,比如说(2,2)而不是(10,10):
>>> list(iter_version())
[((0, 1), (0, 1)), ((0, 1), (1, 0)), ((1, 0), (0, 1)), ((1, 0), (1, 0))]
>>> list(for_loop())
[((0, 1), (0, 1)), ((0, 1), (1, 0))]
如果您在list
电话周围添加itertools.permutations
,它们会再次相同:
>>> list(for_loop_materialized_list())
[((0, 1), (0, 1)), ((0, 1), (1, 0)), ((1, 0), (0, 1)), ((1, 0), (1, 0))]
如果你真的想要iter_version
的结果,我建议你开始想要别的东西。 : - )