2014-10-02 1 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 초 걸린다는 것을 제외하고 아무 것도 보여주지 않습니다.

난 그냥이 같은 루프에 대한 몇 가지 미친 만드는 경우이 거의 즉시 실행

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입니다. 그래도 어떤 시스템에서는 3628800 * 10 = 36288000 순열을 계산하는 데 16 초 걸리는 것을 상상할 수 있습니다. (당신이 iter_version를 호출하는 방법이 표시되지 않기 때문에, 당신은 내가 추측 만 next(iter_version()) 또는 뭔가 후 수 있습니다 그래서 그것을 얻을 훨씬 간단한 방법이 있는지하지만 ..) iter_version 사이

진짜 차이 for_loopitertools.product이 Cartesian 제품을 구체화하지 않지만 이 각 인수를 먼저 목록으로 변환하고 반복적으로 반복 할 수 있다는 것입니다. for_loop에서 반복자를 다 써 버리고 거의 많은 작업을 수행하지 않습니다. 하지만, 그들은 다시 동등하게,

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

당신이 itertools.permutations 호출 주위에 list을 추가하는 경우 :

대신 (10,10)의, 작은 케이스 참조 (2,2) 말을 아마 쉽게 : 당신이 정말로 iter_version의 결과를 원하는 경우에

>>> list(for_loop_materialized_list()) 
[((0, 1), (0, 1)), ((0, 1), (1, 0)), ((1, 0), (0, 1)), ((1, 0), (1, 0))] 

, 난 당신이 대신 다른 뭔가를 원하는 시작하는 것이 좋습니다. :-)

+0

감사합니다. @DSM. 'next (iter_version())'은 내 바탕 화면에서 16 초 걸린다. 파이썬의 이슈 트래커 인 http://bugs.python.org/issue10109에서이 버그를 발견했습니다. itertools.product'는 반복문을 나중에 마술을 수행하는 것보다 먼저 변환 할 것입니다. – yegle

+0

내 특정 사용 사례에 대한 해결책을 찾았으며 아래에 게시 할 것입니다. – yegle

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