2016-09-17 20 views
1

假設我有一個看起來像Python列表:Python的組合

[1, 2, 3, 4] 

我希望能夠返回含有兩個或多個號碼的所有組合列表的列表。值的順序並不重要,所以1,2與2,1相同。我還想返回另一個包含每個組合中不具備的值的列表。例如:

Combination 1,2/Remainder 3,4 
Combination 2,3/Remainder 1,4 
Combination 1,2,3/Remainder 4 
Combination 1,2,3,4/ Remainder - 

爲返回列表上面會

combination = [[1,2], [2,3], [1,2,3], [1,2,3,4]] 
remainder = [[3,4], [1,4], [4], []] 

我只出了幾個例子...

我認識到,第一部分大概可以實現使用itertools.combinations但我怎樣才能返回沒有循環的組合中使用的那些值?

回答

2

時的想法大廈由Nunzio,但不是在一定範圍內,以二進制數字轉換,你可以使用itertools.product讓所有組合10(或TrueFalse),然後用它作爲過濾「ins」和「outs」的掩碼。

>>> lst = [1,2,3] 
>>> products = list(product([1,0], repeat=len(lst))) 
>>> [[lst[i] for i, e in enumerate(p) if e] for p in products] 
[[1, 2, 3], [1, 2], [1, 3], [1], [2, 3], [2], [3], []] 
>>> [[lst[i] for i, e in enumerate(p) if not e] for p in products] 
[[], [3], [2], [2, 3], [1], [1, 3], [1, 2], [1, 2, 3]] 

你也可以定義爲enumerate理解的功能,並做兩個部分一氣呵成:在「範圍」列表中,你可以

>>> mask = lambda lst, p, v: [lst[i] for i, e in enumerate(p) if e == v] 
>>> [(mask(lst, p, 1), mask(lst, p, 0)) for p in product([1,0], repeat=len(lst))] 
[([1, 2, 3], []), 
([1, 2], [3]), 
([1, 3], [2]), 
([1], [2, 3]), 
([2, 3], [1]), 
([2], [1, 3]), 
([3], [1, 2]), 
([], [1, 2, 3])] 

如果您只想組合,帶2個或更多添加一個條件:

>>> [(mask(lst, p, 1), mask(lst, p, 0)) for p in product([1,0],repeat=len(lst)) if sum(p) >= 2] 

或者使用numpy陣列和利用numpy先進的索引:

>>> arr = np.array([1,2,3]) 
>>> [(arr[p==1], arr[p==0]) for p in map(np.array, product([1,0], repeat=len(arr)))] 
[(array([1, 2, 3]), array([])), 
(array([1, 2]), array([3])), 
(array([1, 3]), array([2])), 
(array([1]), array([2, 3])), 
(array([2, 3]), array([1])), 
(array([2]), array([1, 3])), 
(array([3]), array([1, 2])), 
(array([]), array([1, 2, 3]))] 
+0

真的很好的實施! –

+0

我喜歡這個解決方案!像夢一樣工作!謝謝 – Mark

2

可以採取差集:

l = set([1, 2, 3, 4]) 

for i in range(len(l)+1): 
    for comb in itertools.combinations(l, i): 
     print(comb, l.difference(comb)) 

() {1, 2, 3, 4} 
(1,) {2, 3, 4} 
(2,) {1, 3, 4} 
(3,) {1, 2, 4} 
(4,) {1, 2, 3} 
(1, 2) {3, 4} 
(1, 3) {2, 4} 
(1, 4) {2, 3} 
(2, 3) {1, 4} 
(2, 4) {1, 3} 
(3, 4) {1, 2} 
(1, 2, 3) {4} 
(1, 2, 4) {3} 
(1, 3, 4) {2} 
(2, 3, 4) {1} 
(1, 2, 3, 4) set() 
+0

請注意,只有當列表中不包含重複項時,設置差異才起作用。 –

1

假設有這種載體[1 6 3]

可以從0到2^3-1,其中圖3是產生所有的數字的len([1 6 3])

0 
1 
2 
3 
4 
5 
6 
7 

後,你可以把這些數字轉換爲二進制:

0 0 0 
0 0 1 
0 1 0 
0 1 1 
1 0 0 
1 0 1 
1 1 0 
1 1 1 

把你的載體在所產生的序列的頂部:

[1 6 3] 
0 0 0 
0 0 1 
0 1 0 
0 1 1 
1 0 0 
1 0 1 
1 1 0 
1 1 1 

每行組合是在1s的同一位置,並在剩餘的一個是在的位置的數附加0。

如此,例如,看着4號線:

Combination: [6,3] 
Remainder: [1] 

底:

Combination: [],[3],[6],[6,3],[1],[1,3],[1,6],[1,6,3] 
Remainder: [1,6,3],[1,3],[1],[6,3],[6],[3],[] 

下面的代碼:

vec=[1,3,6] 
binary_vec = [format(i,'b').zfill(len(vec)) for i in range(2**len(vec))] 
print([[vec[i] for i,y in enumerate(x) if y != "0"] for x in binary_vec]) 
print([[vec[i] for i,y in enumerate(x) if y == "0"] for x in binary_vec]) 

輸出:

enter image description here

看看還在我在這個崗位回答:

Determine list of all possible products from a list of integers in Python

+0

有趣的方法。你能否也提供一些代碼?此外,你可以使用'itertools.product([True,False],repeat = 3)'而不是轉換爲二進制。 –

+0

@tobias_k謝謝!我不知道這個函數:itertools.product([True,False],repeat = 3)!我還提供了代碼。 –