2009-11-05 14 views
6

Tengo una lista de tuplas, por ejemplo:cómo el código de una función similar a itertools.product en Python 2.5

A=[(1,2,3), (3,5,7,9), (7)] 

y quiero generar todas las permutaciones con un artículo de cada tupla.

1,3,7 
1,5,7 
1,7,7 
... 
3,9,7 

Puedo tener cualquier cantidad de tuplas y una tupla puede tener cualquier cantidad de elementos. Y no puedo usar itertools.product() porque Python 2.5.

+0

Tenga en cuenta que tendrá que volver a definir su A. Cuando dice 'A = [(1,2,3), (3,5,7,9), (7)]' 'la (7) 'al final se evalúa como un número entero, no como una tupla. Por lo tanto, no es iterable, y 'product (* A)' lanzará un TypeError. Si dice 'A = (1,2,3), (3,5,7,9), (7,)]', entonces 'product (* A)' funcionará. – unutbu

+0

Ok, ya veo, pero este es un ejemplo demasiado simple. Tengo A como una lista de listas de tuplas de 3 números. Pero quiero eliminar la lista externa y obtener A = listas de tuplas de 3 números. ¿Cómo puedo hacer eso? Es mejor hacer de esto una nueva pregunta para principiantes, creo yo. – lgwest

Respuesta

13

documentos de itertools.product tienen un ejemplo de cómo implementarlo en py2.5:

def product(*args, **kwds): 
    # product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy 
    # product(range(2), repeat=3) --> 000 001 010 011 100 101 110 111 
    pools = map(tuple, args) * kwds.get('repeat', 1) 
    result = [[]] 
    for pool in pools: 
     result = [x+[y] for x in result for y in pool] 
    for prod in result: 
     yield tuple(prod) 
+0

Aparte de que '(* args, repeat = 1)' no funciona en Python 2.5 ... – ephemient

+0

solucionado eso, he copiado accidentalmente el ejemplo de documentos py3.1. – SilentGhost

4

La documentación itertools contiene el código completo que muestra lo que cada función es equivalente a. La implementación product es here.

+0

Gracias, tenía que ayunar para preguntar, creo. – lgwest

5
def product(*iterables): 
    """ Equivalent of itertools.product for versions < 2.6, 
     which does NOT build intermediate results. 
     Omitted 'repeat' option. 
     product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy 
    """ 
    nIters = len(iterables) 
    lstLenths = [] 
    lstRemaining = [1] 
    for i in xrange(nIters-1,-1,-1): 
     m = len(iterables[i]) 
     lstLenths.insert(0, m) 
     lstRemaining.insert(0, m * lstRemaining[0]) 
    nProducts = lstRemaining.pop(0) 

    for p in xrange(nProducts): 
     lstVals = [] 

     for i in xrange(nIters): 
      j = p/lstRemaining[i]%lstLenths[i] 
      lstVals.append(iterables[i][j]) 
     yield tuple(lstVals) 
2

Al jugar con los generadores, yo también encontré una versión de itertools.product, y es casi tan rápido como el (nativo) versión de la biblioteca, mientras que ser 100% compatible con él, y no se acumula resultados intermedios :

def product(*args, **kwds): 
    "Alternative fast implementation of product for python < 2.6" 
    def cycle(sequence, uplevel): 
     while True: 
      vals = next(uplevel) # advance upper level, raises if done 
      it = iter(sequence) # (re-)start iteration of current level 
      try: 
       while True: yield vals + (next(it),) 
      except StopIteration: 
       pass 

    step = iter(((),))    
    for pool in map(tuple, args)*kwds.get('repeat', 1): 
     step = cycle(pool, step) # build stack of iterators 
    return step 

con Python 2.7.3, encontré el rendimiento sea muy bueno (por lo general sólo alrededor de un factor de 5-10 lento con esencialmente el mismo uso de la memoria).

>>> import itertools as itt 
>>> timeit for _ in itt.product(range(20), range(3), range(150)): pass 
1000 loops, best of 3: 221 µs per loop 
>>> timeit for _ in product(range(20), range(3), range(150)): pass 
1000 loops, best of 3: 1.14 ms per loop 
+0

Usar una prueba/excepto para finalizar un ciclo no es excelente. Básicamente, confías en un error para cortocircuitar tu ciclo. –

+0

No estoy de acuerdo con la acusación de que estoy abusando de las condiciones de "error" para salir del bucle - 'StopIteration' es una condición válida para verificar en una construcción de bucle ya que se usa internamente cuando termina un bucle. Tenga en cuenta que las excepciones y 'StopIteration' en particular tienen un uso ligeramente más amplio en Python que en C++, cf. también el Zen de Python. – summentier

Cuestiones relacionadas