2012-05-18 16 views
9

mam dwie następujące listy:python: dziwne elementy listy kombinacja

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

I chciałby mieć wszystkie wykazy 5 elementów utrzymujących porządek tylko l1. Powiedzieć:

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

Zauważ, że kolejność l1 jest ważne i l2 nie jest. l2 elementy przechodzą przez pozycje l1 + l2, ​​ale ważna jest tylko kolejność l1. Walczę z tym. Każda pomoc jest doceniana.

+7

@Marcin: Naprawdę nie lubię tego pytania; po co ludzie mieliby zadawać pytanie, gdyby nie mieli problemów z ustaleniem, od czego zacząć? Jest kilka pytań, które zasługują na to (pytania "wykonaj moją pracę domową"), ale nie wydaje mi się, że to jedna z nich. – ninjagecko

+3

To nie jest moja praca domowa. Jest to nadmierne uproszczenie mojego problemu. Pracuję z wyrównaniem sekwencji białka i utknę. Nie mogę się dowiedzieć, jak najlepiej rozwiązać ten problem. Dzięki i tak. – fred

+0

@ninjagecko (a) Niezależnie od tego, czy jest to praca domowa, oznacza to "napisanie dla mnie jakiegoś kombinatorycznego kodu za darmo" (b) jakiś kod oświetla zarówno cel, jak i konkretny problem. – Marcin

Odpowiedz

0

Próbowałem coś za pomocą uchwytu na klasę dla l1 i itertools.permutations, ale zawierały duplikaty.

Więc próbuje ponownie, jest to najprostszy byłem w stanie uzyskać go:

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 

Uzyskano

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

Jednym z lepszych sposobów podejścia do tego, jak sądzę, byłoby zachować [1,2,3] taką, jaka jest, a następnie, dla "x", rozpoznać, że istnieją cztery lokalizacje, w które można je wstawić (przed "1", przed "2", ... po "3") . Następnie, po wstawieniu "x", jest teraz 5 miejsc do wstawienia "y" (trzy, w których "x" nie zostało wstawione, plus przed "x" i po "x"). Użyj zagnieżdżonej pętli, aby wstawić "x" i "y" w każdej możliwej pozycji. Jako bonus, destylacja pętli zagnieżdżonej staje się zrozumiała ...

4

Jednym ze sposobów na to jest użycie itertools.combinations, aby wybrać indeksy z końcowej listy, w której zamierzasz umieścić elementy l1. Następnie, dla każdego z tych wyborów, użyj itertools.permutations, aby znaleźć wszystkie permutacje elementów na drugiej liście. Następnie przejrzyj obie te listy, wybierając jeden z nich w zależności od tego, czy indeks ma być elementem dla elementu l1 czy 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) ] 

Wyjście będzie:

[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

Następnie, aby uzyskać spójną kolejność '[1, 2, 3]', wystarczy użyć 'odwróconego'? – Darthfett

+0

@Darthfett: oops, miałem na myśli 'pop (0)' zamiast 'pop()' - naprawiono teraz –

+0

Myślę, że 'odwrócony' może dać lepszą wydajność, ponieważ' pop (0) 'jest O (n), natomiast' pop() 'to O (1). Biorąc pod uwagę, że przeglądasz wszystkie elementy z list, zaoszczędzisz obliczenia (co może być ważne, gdy znajdujesz się w pętli kombinacyjnej permutacji). – Darthfett

4

Ja nazywam to przeplatając l1 z (permutacje L2). Możesz to zrobić w dwóch krokach: wybierając pozycje, a następnie permutując pozycje. W przypadku punktów wstawiania można użyć podejścia opartego na masce (permutations([True,True,False,False,False])) lub podejścia opartego na indeksie (product(*[range(5)]*2)). Nie mam jeszcze tej drugiej techniki do pracy.

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

edit: Ach, ta ostatnia technika wspomniałem został prawidłowo wdrożony przez Marka Longair na https://stackoverflow.com/a/10655695/711085 (to jest o wiele bardziej wydajny niż tej techniki)

+0

Dlaczego nie użyjesz 'itertools.repeat' zamiast' [0] * 'i' [1] * '? – rubik

+0

@rubik: czytelność, a i tak będą musiały zostać rozwinięte, aby przekazać połączenie do "permutacji" – ninjagecko

+0

Problem został rozwiązany. Bardzo dziękuję za pomoc. – 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]) 

produkuje:

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