2011-02-05 46 views
5

所有組合我有兩套方案:測試在Python

optionList1 = [a1,a2,a3,...,an] 
optionList2 = [b1,b2,b3,...,bn] 

在optionlists元素的數量不一定相等,我必須從第一optionlist選擇兩次。我如何確保我已經嘗試了第一個列表中的兩個選項和第二個列表中的一個選項的每個組合。下面是一個示例選擇...

selectedOptions = [an1,an2,bn] 
+1

對不起,但我有點不清楚你想做什麼。你是否需要一個元素的所有可能組合的表格,其中沒有來自同一個列表的元素?任何節點是否應該是None? – fncomp 2011-02-05 09:18:44

+0

我想我很慢找出你想要的東西。 – fncomp 2011-02-05 09:22:45

回答

6

假設你不想從列表1的重複條目,這裏有一臺發電機,你可以用它來遍歷所有組合:

def combinations(list1, list2): 
    return ([opt1, opt2, opt3] 
      for i,opt1 in enumerate(list1) 
      for opt2 in list1[i+1:] 
      for opt3 in list2) 

然而,這並沒有選擇相同的選項list1以不同的順序排列。如果你想同時獲得〔A1,A2,B1]和[A2,A1,B1]那麼你可以使用:

def combinations(list1, list2): 
    return ([opt1, opt2, opt3] 
      for opt1 in list1 
      for opt2 in list1 
      for opt3 in list2 if opt1 != opt2) 
2

一種方法是使用itertools.product

for x, y, z in itertools.product(optionlist1,optionlist1,optionlist2): 
    print x,y,z 
+0

這不會嘗試所有的組合。相反,它匹配列表中的索引,如果兩者長度相同,則只返回(a1,a1,b1),(a2,a2,b2)....(an,an,bn)。 – 2011-02-05 09:24:38

+0

@Peter。是的,我只是用正確的答案更新它。我發現你已經指出了正確的答案。 – 2011-02-05 09:29:02

+0

您不需要在列表中添加空值。 itertools.product()可以處理不同長度的列表(或迭代器)。 – 2011-02-05 09:40:25

6

您可以使用itertools.product這一點。它返回所有可能的組合。

例如

for a1, a2, b in itertools.product(optionlist1,optionlist1,optionlist2): 
    do_something(a1,a2,b) 

這將產生 「雙打」 爲[A1,A1,B2]和[A2,A3,B2],[A3,A2,B2。你可以用過濾器來解決這個問題。下面防止任何雙打*:

for a1,a2,b in itertools.ifilter(lambda x: x[0]<x[1], itertools.product(optionlist1,optionlist1,optionlist2)): 
    do_something(a1,a2,b) 

(*),這是假設的選項具有一些自然排序,將與所有原始值的情況。

shanganswer也很好。我寫了一些代碼,對它們進行比較:

from itertools import ifilter, product 
import random 
from timeit import repeat 

def generator_way(list1, list2): 
    def combinations(list1, list2): 
     return ([opt1, opt2, opt3] 
       for i,opt1 in enumerate(list1) 
       for opt2 in list1[i+1:] 
       for opt3 in list2) 
    count = 0 
    for a1,a2,b in combinations(list1,list2): 
     count += 1 

    return count 

def itertools_way(list1,list2): 
    count = 0 
    for a1,a2,b in ifilter(lambda x: x[0] < x[1], product(list1,list1,list2)): 
     count += 1 
    return count 

list1 = range(0,100) 
random.shuffle(list1) 
list2 = range(0,100) 
random.shuffle(list2) 

print sum(repeat(lambda: generator_way(list1,list2),repeat = 10, number=1))/10 
print sum(repeat(lambda: itertools_way(list1,list2),repeat = 10, number=1))/10 

,其結果是:

0.189330005646 
0.428138256073 

所以產生方法是更快。然而,速度並不是一切。我個人認爲我的代碼「更清潔」,但選擇是你的!

(順便說一句,他們給兩個相同的數,所以兩者同樣都是正確的。)

3

這聽起來像你對我正在尋找itertools.product()

>>> options_a = [1,2] 
>>> options_b = ['a','b','c'] 
>>> list(itertools.product(options_a, options_a, options_b)) 
[(1, 1, 'a'), 
(1, 1, 'b'), 
(1, 1, 'c'), 
(1, 2, 'a'), 
(1, 2, 'b'), 
(1, 2, 'c'), 
(2, 1, 'a'), 
(2, 1, 'b'), 
(2, 1, 'c'), 
(2, 2, 'a'), 
(2, 2, 'b'), 
(2, 2, 'c')] 
6

組合來自itertoolsproductpermutations假設你不想從第一個列表中複製:

>>> from itertools import product,permutations 
>>> o1 = 'a1 a2 a3'.split() 
>>> o2 = 'b1 b2 b3'.split() 
>>> for (a,b),c in product(permutations(o1,2),o2): 
...  print a,b,c 
... 
a1 a2 b1 
a1 a2 b2 
a1 a2 b3 
a1 a3 b1 
a1 a3 b2 
a1 a3 b3 
a2 a1 b1 
a2 a1 b2 
a2 a1 b3 
a2 a3 b1 
a2 a3 b2 
a2 a3 b3 
a3 a1 b1 
a3 a1 b2 
a3 a1 b3 
a3 a2 b1 
a3 a2 b2 
a3 a2 b3