2012-05-18 15 views
9

Ho le due seguenti liste:pitone: strano elementi della lista combinazione

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

E vorrebbe avere tutte le liste di 5 elementi che mantengono l'ordine di soli 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] 

Si osservi che l'ordine di l1 è importante e l2 non lo è. Gli elementi l2 corrono oltre le posizioni l1 + l2 ma solo l'ordine di l1 è importante. Sono alle prese con questo. Qualsiasi aiuto è apprezzato.

+7

@Marcin: Non mi piace davvero quella domanda; perché la gente dovrebbe fare una domanda se non stessero avendo problemi a capire da dove cominciare? Ci sono alcune domande che meritano (domande "faccio i compiti"), ma non credo che questo sia uno di questi. – ninjagecko

+3

Questo non è il mio lavoro a casa. Questa è una semplificazione eccessiva del mio problema. Lavoro con allineamenti di sequenze proteiche e rimango bloccato. Non riesco a capire come il modo migliore per affrontare questo problema. Grazie comunque. – fred

+0

@ninjagecko (a) Indipendentemente dal fatto che si tratti di compiti a casa, ciò equivale a "scrivere un codice combinatorio per me gratuitamente" (b) un codice illumina sia l'obiettivo che il problema specifico. – Marcin

risposta

0

Ho provato qualcosa utilizzando un segnaposto di classe per l1 e itertools.permutations ma con duplicati.

Così, provando ancora una volta, questo è il più semplice sono stato in grado di farlo:

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 

Cedendo:

['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

Uno dei modi migliori per avvicinarsi a questo, credo, sarebbe mantenere [1,2,3] come è, e quindi, per 'x', riconoscere che ci sono quattro posizioni che potrebbero essere inserite (prima di '1', prima di '2', ... dopo '3') . Quindi, una volta che 'x' è stato inserito, ora ci sono 5 posti per inserire 'y' (i tre dove 'x' non è stato inserito, più prima di 'x' e dopo 'x'). Usa un ciclo annidato per inserire 'x' e 'y' in ogni posizione possibile. Come bonus, distillare il ciclo annidato in una comprensione ...

4

Un modo per fare ciò è utilizzare itertools.combinations per selezionare gli indici dell'elenco finale in cui inserire gli elementi di l1. Quindi, per ciascuna di queste opzioni, utilizzare itertools.permutations per trovare tutte le permutazioni degli elementi nel secondo elenco. Quindi passa attraverso entrambi gli elenchi, selezionando il fronte di entrambi, a seconda che l'indice sia uno che dovrebbe essere per un elemento per 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) ] 

Il risultato sarebbe:

[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

Quindi per ottenere l'ordine coerente di '[1, 2, 3]', dovresti semplicemente usare 'invertito'? – Darthfett

+0

@Darthfett: oops, intendevo 'pop (0)' invece di 'pop()' - risolto ora –

+0

Penso che 'reverseed' potrebbe dare prestazioni migliori, dato che' pop (0) 'è O (n), mentre' pop() 'è O (1). Dato che stai facendo scoppiare tutti gli elementi dagli elenchi, salverebbe il calcolo (che potrebbe essere importante quando ti trovi all'interno di un ciclo di permutazione della combinazione). – Darthfett

4

Io chiamo questo l1 inframmezzando con (le permutazioni di l2). Puoi farlo in due passaggi: scegliere le posizioni, quindi permutare le posizioni. Per i punti di inserimento, è possibile utilizzare un approccio basato su maschera (permutations([True,True,False,False,False])) o un approccio basato su indice (product(*[range(5)]*2)). Non ho ancora ottenuto la seconda tecnica per lavorare.

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) 

Demo:

[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'] 

modificare: Ah, quest'ultima tecnica che ho citato è stato correttamente attuato da Mark Longair a https://stackoverflow.com/a/10655695/711085 (è molto più efficiente di questa tecnica)

+0

Perché non usi 'itertools.repeat' invece di' [0] * 'e' [1] * '? – rubik

+0

@rubik: leggibilità, e dovranno essere espansi comunque per alimentare la chiamata a 'permutations' – ninjagecko

+0

Il problema è stato risolto. Grazie mille per l'aiuto. – 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]] 
Problemi correlati