2012-05-18 154 views
9

我有兩個以下列表:蟒蛇:怪異列表元素組合

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

,並希望有5個元素保留的唯一l1順序的所有列表。你說:

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

觀察到的l1的順序很重要,l2不是。 l2元素運行在l1 + l2的位置,但只有l1的順序很重要。 我正在努力與此。任何幫助表示讚賞。

+7

@Marcin:我真的不喜歡那個問題;爲什麼人們會問自己是否無法找出從哪裏開始?有一些問題值得(「做我的作業」問題),但我不覺得這是其中之一。 – ninjagecko

+3

這不是我的家庭作業。這是對我的問題的過度簡化。我使用蛋白質序列比對工作並卡住。無法弄清楚如何處理這個問題的最佳方法。不管怎麼說,還是要謝謝你。 – fred

+0

@ninjagecko(a)不管它是否是家庭作業,這相當於「爲我免費編寫一些組合代碼」(b)一些代碼說明了目標和具體問題。 – Marcin

回答

0

我嘗試了一些使用l1和itertools.permutations的類佔位符,但它有重複的內容。

所以,再次嘗試,這是最簡單的我已經能夠得到它:

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 

產量:

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

其中一個更好的方式來處理這個問題,我認爲,將原樣保留[1,2,3],然後,對於'x',識別它可以插入的四個位置(在'1'之前,'2'之前,...在'3'之後)) 。然後,插入'x'後,現在有5個地方插入'y'(未插入'x'的三個地方,加上'x'之前和'x'之後)。使用嵌套循環在每個可能的位置插入'x'和'y'。作爲獎勵,提取嵌套循環成理解...

4

這樣做的一種方法是使用itertools.combinations挑選出最終列表的索引,您將放入其中的元素l1。然後,對於每個選項,使用itertools.permutations查找第二個列表中的所有項目排列。然後通過這兩個列表,從任一個的前面選取,取決於索引是否應該是針對l1l2的元素。

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

輸出將是:

[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

然後爲了得到'[1,2,3]'的一致性順序,你只需要使用'reversed'? – Darthfett

+0

@Darthfett:oops,我的意思是'pop(0)'而不是'pop()' - 現在修復 –

+0

我認爲'reversed'可能會給出更好的性能,因爲'pop(0)'是O(n) pop()'是O(1)。假設你彈出列表中的所有項目,它將節省計算(當你處於組合排列循環中時,這可能很重要)。 – Darthfett

4

我把這個點綴L1(L2的排列)。您可以分兩步進行:選擇職位,然後排列職位。對於插入點,可以使用基於掩碼的方法(permutations([True,True,False,False,False]))或基於索引的方法(product(*[range(5)]*2))。還沒有得到後者的技術工作。

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) 

演示:

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

編輯:啊,我所提到的後一種技術被正確由Mark Longair在https://stackoverflow.com/a/10655695/711085實現(這是更有效的比這個技術)

+0

爲什麼不使用'itertools.repeat'而不是'[0] *'和'[1] *'? – rubik

+0

@ rubik:可讀性,無論如何他們將不得不擴大,以將呼叫提供給'permutations' – ninjagecko

+0

問題已經解決。非常感謝您的幫助。 – 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]) 

產生於:

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