2012-05-18 8 views
9

tengo las dos listas siguientes:pitón: extraña combinación de elementos de la lista

l1 = [1, 2, ,3] 
l2 = [x, y] 

Y quisiera tener todas las listas de 5 elementos de mantenimiento de orden de sólo l1. Di:

[x, y, 1, 2, 3], 
[x, 1, y, 2, 3], 
[x, 1, 2, y, 3], 
[x, 1, 2, 3, y], 
[y, x, 1, 2, 3], 
[y, 1, x, 2, 3], 
[y, 1, 2, x, 3], 
[y, 1, 2, 3, x], 
[1, x, y, 2, 3], 
[1, x, 2, y, 3], 
[1, x, 2, 3, y], 
[1, y, x, 2, 3], 
[1, y, 2, x, 3], 
[1, y, 2, 3, x], 
... 
[1, 2, 3, y, x], 
... 
[1, 2, 3, x, y] 

Observe que el orden de l1 es importante y no es l2. l2 elementos se ejecutan en l1 + l2 posiciones, pero solo el orden de l1 es importante. Estoy luchando con esto. Cualquier ayuda es apreciada.

+7

@Marcin: Realmente no me gusta esa pregunta; ¿Por qué las personas harían una pregunta si no tuvieran problemas para averiguar por dónde empezar? Hay algunas preguntas que merecen esa (preguntas de "hacer las tareas"), pero no creo que este sea uno de ellos. – ninjagecko

+3

Este no es mi trabajo a domicilio. Esto es una simplificación excesiva de mi problema. Trabajo con alineamientos de secuencias de proteínas y me quedo atascado. No puedo entender cómo es la mejor manera de lidiar con este problema. Gracias de cualquier manera. – fred

+0

@ninjagecko (a) Sea o no una tarea, esto equivale a "escribir algún código combinatorio gratis" (b) algún código ilumina tanto el objetivo como el problema específico. – Marcin

Respuesta

0

Intenté algo utilizando un marcador de posición de clase para l1 y itertools.permutations pero tenía duplicados.

Por lo tanto, tratando de nuevo, esta es la más sencilla que he podido conseguirlo:

from itertools import combinations, permutations 

l1 = [1, 2, 3] 
l2 = ["x", "y"] 
r = range(len(l1)+len(l2)) 
for combo in combinations(r,len(l2)): 
    for permu in permutations(l2): 
    i1 = iter(l1).next 
    i2 = iter(permu).next 
    row = [ i2() if i in combo else i1() for i in r ] 
    print row 

Rendimiento:

['x', 'y', 1, 2, 3] 
['y', 'x', 1, 2, 3] 
['x', 1, 'y', 2, 3] 
['y', 1, 'x', 2, 3] 
['x', 1, 2, 'y', 3] 
['y', 1, 2, 'x', 3] 
['x', 1, 2, 3, 'y'] 
['y', 1, 2, 3, 'x'] 
[1, 'x', 'y', 2, 3] 
[1, 'y', 'x', 2, 3] 
[1, 'x', 2, 'y', 3] 
[1, 'y', 2, 'x', 3] 
[1, 'x', 2, 3, 'y'] 
[1, 'y', 2, 3, 'x'] 
[1, 2, 'x', 'y', 3] 
[1, 2, 'y', 'x', 3] 
[1, 2, 'x', 3, 'y'] 
[1, 2, 'y', 3, 'x'] 
[1, 2, 3, 'x', 'y'] 
[1, 2, 3, 'y', 'x'] 
1

Una de las mejores maneras de abordar esto, creo, sería mantener [1,2,3] como está, y luego, para 'x', reconocer que hay cuatro ubicaciones donde podría insertarse (antes de '1', antes de '2', ... después de '3') . Luego, una vez que se ha insertado 'x', ahora hay 5 lugares para insertar 'y' (los tres donde 'x' no se insertó, más antes de 'x' y después de 'x'). Use un bucle anidado para insertar 'x' e 'y' en cada posición posible. Como beneficio adicional, destilar el bucle anidado en una comprensión ...

4

Una forma de hacer esto es utilizar itertools.combinations de seleccionar los índices de la lista final en la que vas a poner los elementos de l1. Luego, para cada una de esas opciones, use itertools.permutations para encontrar todas las permutaciones de elementos en la segunda lista. Luego revise ambas listas, seleccionando cualquiera de las dos dependiendo de si el índice es uno que se supone que es para un elemento para l1 o l2.

from itertools import combinations, permutations 

l1 = [1, 2, 3] 
l2 = ["x", "y"] 

n = len(l1) + len(l2) 

for c in combinations(range(0, n), len(l1)): 
    cs = set(c) 
    for p in permutations(l2): 
     l1i = iter(l1) 
     l2i = iter(p) 
     print [ l1i.next() if i in cs else l2i.next() for i in range(0,n) ] 

La salida sería:

[1, 2, 3, 'x', 'y'] 
[1, 2, 3, 'y', 'x'] 
[1, 2, 'x', 3, 'y'] 
[1, 2, 'y', 3, 'x'] 
[1, 2, 'x', 'y', 3] 
[1, 2, 'y', 'x', 3] 
[1, 'x', 2, 3, 'y'] 
[1, 'y', 2, 3, 'x'] 
[1, 'x', 2, 'y', 3] 
[1, 'y', 2, 'x', 3] 
[1, 'x', 'y', 2, 3] 
[1, 'y', 'x', 2, 3] 
['x', 1, 2, 3, 'y'] 
['y', 1, 2, 3, 'x'] 
['x', 1, 2, 'y', 3] 
['y', 1, 2, 'x', 3] 
['x', 1, 'y', 2, 3] 
['y', 1, 'x', 2, 3] 
['x', 'y', 1, 2, 3] 
['y', 'x', 1, 2, 3] 
+1

Entonces, para obtener el orden consistente de '[1, 2, 3]', ¿simplemente usarías 'invertido'? – Darthfett

+0

@Darthfett: oops, quise decir 'pop (0)' en vez de 'pop()' - corregido ahora –

+0

Creo que 'reverseed' podría dar mejor rendimiento, ya que' pop (0) 'es O (n), mientras' pop() 'es O (1). Dado que está sacando todos los elementos de las listas, se ahorraría el cálculo (que puede ser importante cuando se está dentro de un bucle de permutación de combinación). – Darthfett

4

Yo llamo a esto L1 intercalando con (las permutaciones de L2). Puedes hacer esto en dos pasos: elegir las posiciones y luego permutar las posiciones. Para los puntos de inserción, puede usar un enfoque basado en máscara (permutations([True,True,False,False,False])) o un enfoque basado en índice (product(*[range(5)]*2)). Aún no he conseguido la última técnica para trabajar.

from itertools import * 

def interspersings(l1,l2): 
    for mask in set(permutations([0]*len(l1) + [1]*len(l2))): # sadly inefficient 
     iters = [iter(l1), iter(l2)] 
     yield [next(iters[which]) for which in mask] 

for perm in permutations(l2): 
    for interspersing in interspersings(l1,perm): 
     print(interspersing) 

Demostración:

[1, 2, 'x', 'y', 3] 
['x', 'y', 1, 2, 3] 
[1, 2, 'x', 3, 'y'] 
[1, 2, 3, 'x', 'y'] 
['x', 1, 'y', 2, 3] 
[1, 'x', 'y', 2, 3] 
[1, 'x', 2, 'y', 3] 
['x', 1, 2, 'y', 3] 
[1, 'x', 2, 3, 'y'] 
['x', 1, 2, 3, 'y'] 
[1, 2, 'y', 'x', 3] 
['y', 'x', 1, 2, 3] 
[1, 2, 'y', 3, 'x'] 
[1, 2, 3, 'y', 'x'] 
['y', 1, 'x', 2, 3] 
[1, 'y', 'x', 2, 3] 
[1, 'y', 2, 'x', 3] 
['y', 1, 2, 'x', 3] 
[1, 'y', 2, 3, 'x'] 
['y', 1, 2, 3, 'x'] 

edición: Ah, la última técnica que he mencionado se ha implementado correctamente por Mark Longair en https://stackoverflow.com/a/10655695/711085 (que es mucho más eficiente que esta técnica)

+0

¿Por qué no usa 'itertools.repeat' en lugar de' [0] * 'y' [1] * '? – rubik

+0

@rubik: legibilidad, y tendrán que ser expandidos de todos modos para alimentar la llamada a 'permutations' – ninjagecko

+0

El problema ha sido resuelto. Muchas gracias por ayudarme. – fred

0
>>> import itertools 
>>> l1 = [1, 2, 3] 
>>> l2 = ['x', 'y', 0, 0, 0] 
>>> l4 = [] 
>>> cyc = itertools.cycle(l1) 
>>> for el in set(itertools.permutations(l2, 5)): 
...  l4.append([cyc.next() if j==0 else j for j in el]) 

produce:

>>> l4 
[[1, 2, 'x', 3, 'y'], 
['y', 'x', 1, 2, 3], 
['x', 1, 'y', 2, 3], 
['x', 1, 2, 'y', 3], 
[1, 2, 3, 'y', 'x'], 
[1, 'y', 2, 3, 'x'], 
[1, 2, 3, 'x', 'y'], 
[1, 'x', 2, 3, 'y'], 
[1, 'y', 'x', 2, 3], 
[1, 2, 'x', 'y', 3], 
[1, 2, 'y', 'x', 3], 
[1, 'x', 2, 'y', 3], 
['y', 1, 2, 'x', 3], 
['x', 1, 2, 3, 'y'], 
[1, 'y', 2, 'x', 3], 
[1, 'x', 'y', 2, 3], 
['y', 1, 2, 3, 'x'], 
['x', 'y', 1, 2, 3], 
[1, 2, 'y', 3, 'x'], 
['y', 1, 'x', 2, 3]] 
Cuestiones relacionadas