Is there a way to get “groups of combinations” of lists that don't overlap, and is exhaustive, using itertools on Python?

心不动则不痛 提交于 2020-08-26 08:27:24

问题


Here's what I mean: if you found all possible 2-element combinations of [1,2,3,4], you would get [1,2], [1,3],[1,4],[2,3],[2,4] and [3,4]

What I want is groups of combinations that don't overlap and include all elements. So for example [[1,2],[3,4]] is an example of one "group", because the elements in both combinations do not overlap, and all possible elements are used. [[1,3],[2,4]] is an example of another "group"

By the way, I'm aware that itertools will allow me to print combinations themselves. So for example, the following code:

combinations = itertools.combinations([1,2,3,4], 2)
for c in combinations:
    print(c)

will output:

(1, 2)
(1, 3)
(1, 4)
(2, 3)
(2, 4)
(3, 4)

But again, that's just giving me combinations. I want GROUPS of combinations that are mutually exclusive and exhaustive with the elements.

Also, I'm sure I'm not using the proper vocabulary. If there is a formal term for anything I'm describing, I would appreciate learning it.

Thanks in advance!


回答1:


These “groups of combinations” might be called set partitions into parts of size k.

I assume that k is divisor of n, so there are p=n/k parts.

Now we can recursively distribute items over parts. To avoid repeated generation of the same partition (like 01 23 45 and 01 45 23), we should restrict places for leading (the smallest) element of every group.

Here I used lastfilled parameter for index of the rightmost filled part, so item 0 always belongs to the 0-th part, item 1 might fall into parts 0 or 1 but not into part 2 and so on. Having intermediate result 01 __ __ we can make only 01 2_ __ at the next level, not 01 __ 2_.

Note that number of such partitions is

NPK(n,k) = n! / ((k!)^p * p!)

and grows fast (280 for n=9,k=3, 1401400 for 15/3). (Found OEIS sequence A060540)

Python code. I used global lists for parts contents and counts of occupied places in them to save memory, so I have to reset counts to previous state after recursive call.

n = 6
k = 2
p = n // k
parts = [[0]*k for _ in range(p)]
cnts = [0]*p

def genparts(m, lastfilled):
    if m == n:
        print(parts)
        return
    for i in range(min(p, lastfilled + 2)):
        if cnts[i] < k:
            parts[i][cnts[i]] = m
            cnts[i] += 1
            genparts(m+1, max(i, lastfilled))
            cnts[i] -= 1

genparts(0, -1)

[[0, 1], [2, 3], [4, 5]]
[[0, 1], [2, 4], [3, 5]]
[[0, 1], [2, 5], [3, 4]]
[[0, 2], [1, 3], [4, 5]]
[[0, 2], [1, 4], [3, 5]]
[[0, 2], [1, 5], [3, 4]]
[[0, 3], [1, 2], [4, 5]]
[[0, 4], [1, 2], [3, 5]]
[[0, 5], [1, 2], [3, 4]]
[[0, 3], [1, 4], [2, 5]]
[[0, 3], [1, 5], [2, 4]]
[[0, 4], [1, 3], [2, 5]]
[[0, 5], [1, 3], [2, 4]]
[[0, 4], [1, 5], [2, 3]]
[[0, 5], [1, 4], [2, 3]]


来源:https://stackoverflow.com/questions/63146515/is-there-a-way-to-get-groups-of-combinations-of-lists-that-dont-overlap-and

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!