2016-09-17 16 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)!我还提供了代码。 –