2012-10-09 8 views
11

tengo una lista de listas y una cadena de separación de esta manera:Obtener cadena unido a la lista de listas de cadenas en Python

lists = [ 
    ['a', 'b'], 
    [1, 2], 
    ['i', 'ii'], 
] 
separator = '-' 

Como resultado Quiero tener una lista de cadenas combinadas con cadena de separación de la cadenas en las listas secundarias:

result = [ 
    'a-1-i', 
    'a-1-ii', 
    'a-2-i', 
    'a-2-ii', 
    'b-1-i', 
    'b-1-ii', 
    'b-2-i', 
    'b-2-ii', 
] 

El pedido en el resultado es irrelevante.

¿Cómo puedo hacer esto?

+0

Por el momento no estoy seguro de cómo conseguir este trabajo de una manera Pythonic agradable y no es tarea;) – Martin

Respuesta

16
from itertools import product 
result = [separator.join(map(str,x)) for x in product(*lists)] 

itertools.product devuelve un iterador que produce el producto cartesiano de las iterables proporcionados. Necesitamos mapstr sobre las tuplas resultantes, ya que algunos de los valores son enteros. Finalmente, podemos unirnos a las tuplas encerradas y arrojar todo dentro de una lista de comprensión (o expresión de generador si se trata de un conjunto de datos grande, y solo lo necesita para la iteración).

+1

1 Gran respuesta hombre - Quiero imprimir eso y ponerlo en mi refrigerador. – RocketDonkey

3
>>> from itertools import product 
>>> result = list(product(*lists)) 
>>> result = [separator.join(map(str, r)) for r in result] 
>>> result 
['a-1-i', 'a-1-ii', 'a-2-i', 'a-2-ii', 'b-1-i', 'b-1-ii', 'b-2-i', 'b-2-ii'] 

Como @jpm señaló, que realmente no necesita para echar list al generador product. Los tuve para ver los resultados en mi consola, pero no son realmente necesarios aquí.

+0

No necesita forzar el producto en un constructor 'list'. 'map' funciona bien en un iterador. Además, no es necesario forzar las tuplas en ese iterador en las listas. 'map' y' join' funcionan bien en tuplas. – jpm

+0

@jpm sí, todavía estaba editando eso. Inicialmente los tuve al intentar en mi consola ver los resultados, debería haberlos eliminado más adelante :) –

+1

Otro punto sobre forzar al iterador a una lista intermedia: si el producto cartesiano se agranda (un escenario completamente posible, a pesar de lo que muestra este ejemplo), es probable que deseemos demorarlo todo en la memoria el mayor tiempo posible. Dependiendo de la aplicación, podemos desear utilizar una expresión de generador en lugar de una lista de comprensión. – jpm

1
["%s%c%s%c%s" % (a, separator, b, separator, c) for a in lists[0] for b in lists[1] for c in lists[2]] 
3

Usted puede hacer esto con órdenes internas:

>>> map(separator.join, reduce(lambda c,n: [a+[str(b)] for b in n for a in c], lists, [[]])) 
['a-1-i', 'b-1-i', 'a-2-i', 'b-2-i', 'a-1-ii', 'b-1-ii', 'a-2-ii', 'b-2-ii'] 
+0

Buen uso de las técnicas funcionales. Si cambia las cláusulas 'para 'de la comprensión, incluso puede coincidir con la salida solicitada por el OP. – jpm

+0

Como punto de interés, esta solución es un poco más lenta que la mía (no es exactamente 2 segundos más de 2,000,000 de repeticiones, a través del tiempo). No es suficiente para preocuparse en casi cualquier aplicación, pero me pareció interesante. – jpm

+0

Gracias. No pensé mucho sobre el orden de los términos, pero el OP dijo que no le importaba la orden. – Benedict

Cuestiones relacionadas