Python 组合

Python Combinations

假设我有一个 Python 列表,如下所示:

[1, 2, 3, 4]

我希望能够 return 包含两个或多个数字的所有组合的列表列表。值的顺序无关紧要,因此 1,2 与 2,1 相同。我还想 return 另一个列表,其中包含每个组合中没有的值。例如:

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

上述 returned 列表为

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

我只展示了几个例子...

我意识到第一部分可能可以使用 itertools.combinations 来实现,但是我如何 return 那些没有在组合中使用的值而不循环?

您可以取套差:

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

假设你有这个向量 [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

对于每一行,在组合中附加与 1 相同位置的数字,在其余部分附加与 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])

输出:

也看看我在这个post中的回答:

基于 的想法,但不是将特定范围内的数字转换为二进制,您可以只使用 itertools.product 来获得 1 和 [= 的所有组合16=] (或 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])]

如果您只想与 "in" 列表中的 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]))]