在Python中将N个项目惰性地划分为K个容器

在Python中将N个项目惰性地划分为K个容器,python,combinatorics,Python,Combinatorics,给出一个算法(或直接的Python代码),该算法将N个项集合的所有分区生成K个bin,这样每个bin至少有一个项。我需要这个,无论是在秩序重要的情况下,还是在秩序不重要的情况下 秩序重要的例子 >>> list(partition_n_in_k_bins_ordered((1,2,3,4), 2)) [([1], [2,3,4]), ([1,2], [3,4]), ([1,2,3], [4])] >>> list(partition_n_in_k_bins_

给出一个算法(或直接的Python代码),该算法将N个项集合的所有分区生成K个bin,这样每个bin至少有一个项。我需要这个,无论是在秩序重要的情况下,还是在秩序不重要的情况下

秩序重要的例子

>>> list(partition_n_in_k_bins_ordered((1,2,3,4), 2))
[([1], [2,3,4]), ([1,2], [3,4]), ([1,2,3], [4])]

>>> list(partition_n_in_k_bins_ordered((1,2,3,4), 3))
[([1], [2], [3,4]), ([1], [2,3], [4]), ([1,2], [3], [4])]

>>> list(partition_n_in_k_bins_ordered((1,2,3,4), 4))
[([1], [2], [3], [4])]
顺序无关紧要的示例

>>> list(partition_n_in_k_bins_unordered({1,2,3,4}, 2))
[{{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}}]
这些函数应该生成惰性迭代器/生成器,而不是列表。理想情况下,他们会使用
itertools
中的原语。我怀疑有一个聪明的解决办法正在我的脑海中闪过


虽然我在Python中要求这样做,但我也愿意翻译一个清晰的算法

您需要一个递归函数来解决这类问题:您获取列表,获取其长度不断增加的子部分,并将相同的过程应用于n-1个列表的剩余尾部

这是我对有序组合的理解

def partition(lista,bins):
    if len(lista)==1 or bins==1:
        yield [lista]
    elif len(lista)>1 and bins>1:
        for i in range(1,len(lista)):
            for part in partition(lista[i:],bins-1):
                if len([lista[:i]]+part)==bins:
                    yield [lista[:i]]+part

for i in partition(range(1,5),1): 
    print i
#[[1, 2, 3, 4]]

for i in partition(range(1,5),2): 
    print i
#[[1], [2, 3, 4]]
#[[1, 2], [3, 4]]
#[[1, 2, 3], [4]]

for i in partition(range(1,5),3):
    print i
#[[1], [2], [3, 4]]
#[[1], [2, 3], [4]]
#[[1, 2], [3], [4]] 

for i in partition(range(1,5),4):
    print i
#[[1], [2], [3], [4]]

Enrico的算法、Knuth的算法和仅我的胶水都需要将返回列表列表或集合集的内容粘贴在一起(如果元素不可散列,则返回列表)


你说的“秩序重要的地方”是什么意思?在这种情况下,你似乎认为这些项目无法区分。问得好。“Where order matters”可能意味着几件事,如果分区被展平,则项目应该与输入的顺序相同(注意[[1]、[2]、[3,4]]的顺序如何为[1,2,3,4])。这些项目是可以区分的。因此,例如,解决方案[[2]、[1]、[3,4]]将无效。在这种情况下,您可以将问题分解为查找项数,然后生成列表-对于这两种情况。在有序情况下,您要查找,而在无序情况下,您要查找。我不确定最优算法是什么,但它们都是经典问题。如果你允许空箱子,对于你的应用程序来说,这些将代表身份。这不包括分区[[1,3],[2,4]]。啊,那么你只解决了第一部分。
def kbin(l, k, ordered=True):
    """
    Return sequence ``l`` partitioned into ``k`` bins.

    Examples
    ========

    The default is to give the items in the same order, but grouped
    into k partitions:

    >>> for p in kbin(range(5), 2):
    ...     print p
    ...
    [[0], [1, 2, 3, 4]]
    [[0, 1], [2, 3, 4]]
    [[0, 1, 2], [3, 4]]
    [[0, 1, 2, 3], [4]]

    Setting ``ordered`` to None means that the order of the elements in
    the bins is irrelevant and the order of the bins is irrelevant. Though
    they are returned in a canonical order as lists of lists, all lists
    can be thought of as sets.

    >>> for p in kbin(range(3), 2, ordered=None):
    ...     print p
    ...
    [[0, 1], [2]]
    [[0], [1, 2]]
    [[0, 2], [1]]

    """
    from sympy.utilities.iterables import (
        permutations, multiset_partitions, partitions)

    def partition(lista, bins):
        #  EnricoGiampieri's partition generator from
        #  http://stackoverflow.com/questions/13131491/
        #  partition-n-items-into-k-bins-in-python-lazily
        if len(lista) == 1 or bins == 1:
            yield [lista]
        elif len(lista) > 1 and bins > 1:
            for i in range(1, len(lista)):
                for part in partition(lista[i:], bins - 1):
                    if len([lista[:i]] + part) == bins:
                        yield [lista[:i]] + part
    if ordered:
        for p in partition(l, k):
            yield p
    else:
        for p in multiset_partitions(l, k):
            yield p