2014-10-02 129 views
0

我需要生成itertool.permutation生成的列表的产品,并使用下面的代码:itertools.product:如何提高性能?

def iter_version(): 
    l = [itertools.permutations(range(10)) for _ in range(10)] 
    g = itertools.product(*l) 
    for i in g: 
    yield i 

但是这个代码是太慢。我的桌面上需要16秒钟。 cProfile除了告诉我这个函数需要16秒钟之外什么也没有显示。

如果我只是创造一些像这样疯狂的for循环:

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

恭喜,我不相信你的第一个代码需要16秒才能运行。有(3628800)^ 10或395940866122425193243875570782668457763038822400000000000000000000,元素将被产生。不过,我可以想象它在某些系统上花费16s来计算3628800 * 10 = 36288000排列。 (既然你不告诉你是如何调用iter_version,你可能只有next(iter_version())什么之后,我想,但如果因此有更简单的方法来得到它。)

iter_version之间的真正区别for_loopitertools.product不实现笛卡尔乘积,但它确实首先将每个参数转换为列表,并且列表可以反复迭代。在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的结果,我建议你开始想别的东西来代替。 :-)

+0

谢谢@DSM。 'next(iter_version())'在我的桌面上需要16秒钟。我在Python的问题追踪器上发现了这个错误:http://bugs.python.org/issue10109 itertools.product会将迭代器先转换为列表,而不是稍后再做。 – yegle 2014-10-02 01:57:50

+0

我发现了一个解决方案,我的具体用例,我会在下面发布。 – yegle 2014-10-02 01:58:38

0

就像@DSM的回答说的那样,itertools.product会将迭代器转换为具体的序列。这可以从http://bugs.python.org/issue10109

加以确认。要解决此问题而不将迭代器转换为列表,我使用了此函数。注意这个函数在使用前使用递归进行测试。

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