python - 如何找到列表S的所有分区为k个子集(可以为空)?

标签 python python-3.x math partition

我有一个唯一元素列表,比方说 [1,2],我想将其拆分为 k=2 个子列表。现在我想要所有可能的子列表:

[ [ [1,2],[] ], [ [1],[2] ], [ [2],[1] ], [ [],[1,2] ] ]

我想分割成 1<=k<=n 个子列表,所以对于 k=1 它将是:

[ [1, 2] ]

如何使用 Python 3 做到这一点?

更新:我的目标是获取 N 个唯一数字列表的所有可能分区,其中每个分区将有 k 个子列表。我想展示比我上面展示的更好的例子,我希望我不会错过任何东西。因此,对于列表 [1, 2, 3] 和 k=2 我想要下一个列表:

[
[ [1,2,3], [] ],
[ [2,3], [1] ],
[ [1,3], [2] ],
[ [1,2], [3] ],
[ [1], [2,3] ],
[ [2], [1,3] ],
[ [3], [2,3] ],
[ [], [1,2,3] ]
] 

更新2:到目前为止,我结合了两个建议,并进行了少量修改,得到了下一个代码:

def sorted_k_partitions(seq, k):
    """Returns a list of all unique k-partitions of `seq`.

    Each partition is a list of parts, and each part is a tuple.

    The parts in each individual partition will be sorted in shortlex
    order (i.e., by length first, then lexicographically).

    The overall list of partitions will then be sorted by the length
    of their first part, the length of their second part, ...,
    the length of their last part, and then lexicographically.
    """
    n = len(seq)
    groups = []  # a list of lists, currently empty

    def generate_partitions(i):
        if i >= n:
            yield list(map(tuple, groups))
        else:
            if n - i > k - len(groups):
                for group in groups:
                    group.append(seq[i])
                    yield from generate_partitions(i + 1)
                    group.pop()

            if len(groups) < k:
                groups.append([seq[i]])
                yield from generate_partitions(i + 1)
                groups.pop()

    result = generate_partitions(0)

    # Sort the parts in each partition in shortlex order
    result = [sorted(ps, key = lambda p: (len(p), p)) for ps in result]
    # Sort partitions by the length of each part, then lexicographically.
    result = sorted(result, key = lambda ps: (*map(len, ps), ps))

    return result

通过这个函数我可以做下一步:

import itertools as it
k=2
S = [1, 2, 3]
for i in (range(k)):
    for groups in sorted_k_partitions(S, k-i):
        for perm in it.permutations(groups+[tuple() for j in range(i)]):
            print(perm)

输出为:

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

我还不确定,这段代码是否给了我正确的解决方案,也许还有其他方法?

最佳答案

这是一个替代解决方案:

def partition_k(l, k):
    n = len(l)
    if k > n:
        raise ValueError("k = {0} should be no more than n = {1}".format(k, n))

    if n == 0:
        yield []
        return

    pos = [0] * n
    while True:
        # generate output for the value
        out = [[] for _ in range(k)]
        for i in range(n):
            out[pos[i]].append(l[i])
        yield out

        #increment the value
        pos[0] += 1
        for i in range(n):
            # should we carry from this digit to the next one?
            if pos[i] == k:
                # overflow of the whole value?
                if i == n - 1:
                    return
                pos[i] = 0
                pos[i + 1] += 1
            else:
                break

n 为列表的长度,k 为分区数。该代码背后的想法是,输出的每一行都可以表示为基k 系统中的n 位数字。每个“数字”表示相应位置的值位于哪个桶中。例如行

[[2,3], [1], [4]]

可以编码为[1,0,0,2],这意味着

  • 1 转到存储桶#1
  • 2 转到存储桶#0
  • 3 转到存储桶 #0
  • 4 转到存储桶#2

显然,每个这样的n位基数k数字代表列表的有效分区,并且每个分区都由某个数字表示。因此,要生成所有分区,我们只需迭代所有这些数字并生成相应的分区。如果您使用数字列表来表示数字(在代码中为 pos),则更容易做到。

关于python - 如何找到列表S的所有分区为k个子集(可以为空)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53937159/

相关文章:

python - AttributeError ("' list'对象没有属性 'keys'“,)在带有sqlachemy的 flask 中

python - re.findall 的结果顺序有保证吗?

Python Django mysqldb 选择带有 unicode 值的

python - Python 中的正则表达式替换

algorithm - 给定三角形 3 条边的长度,计算边中点之间的平均距离

ruby - 将字符串作为表达式求值

python - 如何解决python代码错误(TooManyRedirects : Exceeded 30 redirects)

python-3.x - YOLO v3 的 OpenCV 实现在 GCP 实例上重现异常

events - Python 事件与 tkinter 绑定(bind)

sql - 从数据集 SQL 创建趋势线