有没有一种方法可以使用Python计算集合的所有合法分区?

时间:2019-08-08 05:52:15

标签: python math sympy set-theory

Wiki提供了definition个集合的分区

  

在数学中,集合的分区是将集合的元素分组为非空子集,这样每个元素都恰好包含在一个子集中。

这个例子

集合{1,2​​,3}具有这五个分区

includes()

有没有一种方法可以使用Python计算集合的所有合法分区?

我尝试过the partitions in sympy

{ {1}, {2}, {3} }, sometimes written 1|2|3.
{ {1, 2}, {3} }, or 12|3.
{ {1, 3}, {2} }, or 13|2.
{ {1}, {2, 3} }, or 1|23.
{ {1, 2, 3} }, or 123

我知道了

from sympy.combinatorics.partitions import Partition
a = Partition([1, 2, 3])
a.members

这显然是错误的。

2 个答案:

答案 0 :(得分:3)

如果您使用的是Sympy,则需要sympy.utilities.iterables.multiset_partitions

>>> from sympy.utilities.iterables import multiset_partitions
>>> for p in multiset_partitions([1, 2, 3]):
...     print(p)
...
[[1, 2, 3]]
[[1, 2], [3]]
[[1, 3], [2]]
[[1], [2, 3]]
[[1], [2], [3]]

答案 1 :(得分:1)

作为参考,基于itertools的解决方案可以基于对所有可能的分隔符('|')进行迭代。

from itertools import chain, combinations


def powerset(iterable):
    """
    powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)
    """
    xs = list(iterable)
    # note we return an iterator rather than a list
    return chain.from_iterable(combinations(xs,n) for n in range(len(xs)+1))


def proper_partitions(lst):
    dividers = powerset(range(len(lst) - 1))
    for ix in dividers:
        buf = list()
        i = 0
        for j in ix:
            buf.append(lst[i:j+1])
            i = j + 1
        buf.append(lst[i:])
        yield buf


# In [19]: list(proper_partitions([1,2,3]))                                                                
# Out[19]: [[[1, 2, 3]], [[1], [2, 3]], [[1, 2], [3]], [[1], [2], [3]]]

例如参见here