如何获得集合的所有子集?(电源组)


103

给定一套

{0, 1, 2, 3}

如何产生子集:

[set(),
 {0},
 {1},
 {2},
 {3},
 {0, 1},
 {0, 2},
 {0, 3},
 {1, 2},
 {1, 3},
 {2, 3},
 {0, 1, 2},
 {0, 1, 3},
 {0, 2, 3},
 {1, 2, 3},
 {0, 1, 2, 3}]

Answers:


145

Pythonitertools页面对此有一个精确的powerset配方:

from itertools import chain, combinations

def powerset(iterable):
    "powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"
    s = list(iterable)
    return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))

输出:

>>> list(powerset("abcd"))
[(), ('a',), ('b',), ('c',), ('d',), ('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd'), ('c', 'd'), ('a', 'b', 'c'), ('a', 'b', 'd'), ('a', 'c', 'd'), ('b', 'c', 'd'), ('a', 'b', 'c', 'd')]

如果您不喜欢开头的空元组,则可以更改range语句range(1, len(s)+1)以避免使用0长度的组合。


1
这是我找到的最快的答案,可以将页面上的其他解决方案与此使用Python的timeit模块的解决方案进行比较。但是,在某些情况下,如果您需要修改结果输出(例如,将字母连接起来以形成字符串),请使用生成器编写自定义配方并构建所需的输出(例如,将两个字符串加在一起)会更快。
Ceasar Bautista

为什么s = list(iterable)需要?
杰克·史蒂文斯

@JackStevens,因为可迭代项不可重绕并且不需要__len__实现;试试,powerset((n for n in range(3)))不用列表换行。
霍夫林

1
对于大字符串,这会占用大量内存!
NoobEditor

1
@AlexandreHuat:范围是惰性序列,而不是迭代器。即使没有powerset(range(3))也可以正常工作。s = list(iterable)
user2357112支持Monica

50

这是有关电源组的更多代码。这是从头开始写的:

>>> def powerset(s):
...     x = len(s)
...     for i in range(1 << x):
...         print [s[j] for j in range(x) if (i & (1 << j))]
...
>>> powerset([4,5,6])
[]
[4]
[5]
[4, 5]
[6]
[4, 6]
[5, 6]
[4, 5, 6]

马克·鲁沙科夫(Mark Rushakoff)的评论在这里适用:“如果您不喜欢开头的空元组,请继续。”您可以将range语句更改为range(1,len(s)+1)以避免长度为0的组合”除了在我的情况下更改for i in range(1 << x)for i in range(1, 1 << x)


回到今年以后,我现在将其编写为:

def powerset(s):
    x = len(s)
    masks = [1 << i for i in range(x)]
    for i in range(1 << x):
        yield [ss for mask, ss in zip(masks, s) if i & mask]

然后,测试代码如下所示:

print(list(powerset([4, 5, 6])))

使用yield意味着您无需在单个内存中计算所有结果。在主循环之外预先计算掩码被认为是值得进行的优化。


6
这是一个创造性的答案。但是,我使用timeit对其进行了测量,并将其与Mark Rushakoff进行了比较,发现它的速度明显慢得多。为了生成16次项的幂集100次,我的测量结果是0.55对15.6。
Ceasar Bautista

19

如果您正在寻找一个快速的答案,我刚刚在Google上搜索了“ python power set”,并提出了以下建议:Python Power Set Generator

这是该页面中代码的复制粘贴:

def powerset(seq):
    """
    Returns all the subsets of this set. This is a generator.
    """
    if len(seq) <= 1:
        yield seq
        yield []
    else:
        for item in powerset(seq[1:]):
            yield [seq[0]]+item
            yield item

可以这样使用:

 l = [1, 2, 3, 4]
 r = [x for x in powerset(l)]

现在r是您想要的所有元素的列表,可以进行排序和打印:

r.sort()
print r
[[], [1], [1, 2], [1, 2, 3], [1, 2, 3, 4], [1, 2, 4], [1, 3], [1, 3, 4], [1, 4], [2], [2, 3], [2, 3, 4], [2, 4], [3], [3, 4], [4]]

1
如果输入的数组为空,则上述代码将返回[[][]],以解决将长度检查分开的情况if len(seq) == 0: yield [] elif len(seq) == 1: yield seq yield []
Ayush

3
作为参考,我使用timeit测量了这一点(使用Ayush的编辑),并将其与Mark Rushakoff的答案中的powerset配方进行了比较。在我的机器上,要生成16次项的幂集100次,此算法花费了1.36秒,而Rushakoff花费了0.55。
Ceasar Bautista

时间的复杂度是多少?
CodeQuestor

13
def powerset(lst):
    return reduce(lambda result, x: result + [subset + [x] for subset in result],
                  lst, [[]])

8

powerset有一个改进:

def powerset(seq):
    """
    Returns all the subsets of this set. This is a generator.
    """
    if len(seq) <= 0:
        yield []
    else:
        for item in powerset(seq[1:]):
            yield [seq[0]]+item
            yield item

8

TL; DR(直接进入简化)

我知道我以前已经添加了答案,但是我真的很喜欢我的新实现。我将一个集合作为输入,但是实际上它可以是任何迭代的,并且我返回的是集合的集合,即输入的幂集。我喜欢这种方法,因为它更符合幂集所有子集)的数学定义。

def power_set(A):
    """A is an iterable (list, tuple, set, str, etc)
    returns a set which is the power set of A."""
    length = len(A)
    l = [a for a in A]
    ps = set()

    for i in range(2 ** length):
        selector = f'{i:0{length}b}'
        subset = {l[j] for j, bit in enumerate(selector) if bit == '1'}
        ps.add(frozenset(subset))

    return ps

如果您想确切地在答案中发布输出,请使用以下命令:

>>> [set(s) for s in power_set({1, 2, 3, 4})]
[{3, 4},
 {2},
 {1, 4},
 {2, 3, 4},
 {2, 3},
 {1, 2, 4},
 {1, 2},
 {1, 2, 3},
 {3},
 {2, 4},
 {1},
 {1, 2, 3, 4},
 set(),
 {1, 3},
 {1, 3, 4},
 {4}]

说明

已知功率集的元素数为2 ** len(A),因此可以在for循环中清楚地看到。

我需要将输入(最好是一组)转换为列表,因为一组是唯一无序元素的数据结构,而顺序对于生成子集至关重要。

selector是此算法的关键。请注意,selector它的长度与输入集的长度相同,为了使之成为可能,它使用带填充的f字符串。基本上,这使我可以选择将在每次迭代期间添加到每个子集的元素。假设输入集包含3个元素{0, 1, 2},那么选择器将采用0到7(含)之间的值,二进制形式为:

000 # 0
001 # 1
010 # 2
011 # 3
100 # 4
101 # 5
110 # 6
111 # 7

因此,无论是否应添加原始集合的元素,每个位都可以用作指示符。查看二进制数字,然后将每个数字都视为超集的元素,这1意味着j应添加索引处的元素,并且不应添加0此元素。

我使用集合推导在每次迭代时生成一个子集,并将此子集转换为,frozenset以便可以将其添加到ps(幂集)。否则,我将无法添加它,因为Python中的集合仅包含不可变的对象。

简化版

您可以使用一些python理解来简化代码,因此可以摆脱那些for循环。您还zip可以避免使用j索引,并且代码最终将如下所示:

def power_set(A):
    length = len(A)
    return {
        frozenset({e for e, b in zip(A, f'{i:{length}b}') if b == '1'})
        for i in range(2 ** length)
    }

而已。我喜欢这种算法的原因是它比其他算法更清晰,更直观,因为itertools即使它按预期工作,依靠它看起来也很神奇。


5
def get_power_set(s):
  power_set=[[]]
  for elem in s:
    # iterate over the sub sets so far
    for sub_set in power_set:
      # add a new subset consisting of the subset at hand added elem
      power_set=power_set+[list(sub_set)+[elem]]
  return power_set

例如:

get_power_set([1,2,3])

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

1
power_set在其控制的循环中修改循环变量()是一种非常有问题的做法。例如,假设您编写了此代码,而不是建议的变量修改代码:power_set += [list(sub_set)+[elem]]。然后循环不会终止。
hughdbrown

5

我发现以下算法非常清楚和简单:

def get_powerset(some_list):
    """Returns all subsets of size 0 - len(some_list) for some_list"""
    if len(some_list) == 0:
        return [[]]

    subsets = []
    first_element = some_list[0]
    remaining_list = some_list[1:]
    # Strategy: get all the subsets of remaining_list. For each
    # of those subsets, a full subset list will contain both
    # the original subset as well as a version of the subset
    # that contains first_element
    for partial_subset in get_powerset(remaining_list):
        subsets.append(partial_subset)
        subsets.append(partial_subset[:] + [first_element])

    return subsets

生成功率集的另一种方法是生成所有具有n位的二进制数。作为幂集,带n数字的位数为2 ^ n。该算法的原理是,子集中可能存在或不存在元素,因为二进制数字可能是一个或零,但不能同时存在。

def power_set(items):
    N = len(items)
    # enumerate the 2 ** N possible combinations
    for i in range(2 ** N):
        combo = []
        for j in range(N):
            # test bit jth of integer i
            if (i >> j) % 2 == 1:
                combo.append(items[j])
        yield combo

在上MITx时,我找到了两种算法:6.00.2x计算思维和数据科学概论,我认为这是我所见过的最容易理解的算法之一。


3

我只是想提供最容易理解的解决方案,即反代码高尔夫版本。

from itertools import combinations

l = ["x", "y", "z", ]

def powerset(items):
    combo = []
    for r in range(len(items) + 1):
        #use a list to coerce a actual list from the combinations generator
        combo.append(list(combinations(items,r)))
    return combo

l_powerset = powerset(l)

for i, item in enumerate(l_powerset):
    print "All sets of length ", i
    print item

结果

全部套长0

[()]

全部套长1

[('x',), ('y',), ('z',)]

全套长度2

[('x', 'y'), ('x', 'z'), ('y', 'z')]

全套长度3

[('x', 'y', 'z')]

有关更多信息,请参见itertools文档,以及有关电源集的Wikipedia条目


2

只是一个快速的动力设定刷新器!

X的幂集,简单来说就是X的所有子集的集合,包括空集

示例集X =(a,b,c)

幂集= {{a,b,c},{a,b},{a,c},{b,c},{a},{b},{c},{}}

这是查找功率集的另一种方法:

def power_set(input):
    # returns a list of all subsets of the list a
    if (len(input) == 0):
        return [[]]
    else:
        main_subset = [ ]
        for small_subset in power_set(input[1:]):
            main_subset += [small_subset]
            main_subset += [[input[0]] + small_subset]
        return main_subset

print(power_set([0,1,2,3]))

完全归功于来源


2

这可以很自然地通过itertools.product以下方式完成:

import itertools

def powerset(l):
    for sl in itertools.product(*[[[], [i]] for i in l]):
        yield {j for i in sl for j in i}

1
这个问题给出的最优雅的答案
Arthur B.

1

一种简单的方法是利用2的补数算法利用整数的内部表示。

整数的二进制表示形式为{000,001,010,011,100,101,110,111}对于范围从0到7的数字。对于整数计数器值,将1视为集合中包含的对应元素,将'0'视为整数作为排除,我们可以根据计数顺序生成子集。必须从生成数字0pow(2,n) -1其中n是数组的长度,即二进制表示形式的位数。

基于它的简单子集生成器函数可以编写如下。它基本上依赖

def subsets(array):
    if not array:
        return
    else:
        length = len(array)
        for max_int in range(0x1 << length):
            subset = []
            for i in range(length):
                if max_int & (0x1 << i):
                    subset.append(array[i])
            yield subset

然后可以用作

def get_subsets(array):
    powerset = []
    for i in subsets(array):
        powerser.append(i)
    return powerset

测验

在本地文件中添加以下内容

if __name__ == '__main__':
    sample = ['b',  'd',  'f']

    for i in range(len(sample)):
        print "Subsets for " , sample[i:], " are ", get_subsets(sample[i:])

提供以下输出

Subsets for  ['b', 'd', 'f']  are  [[], ['b'], ['d'], ['b', 'd'], ['f'], ['b', 'f'], ['d', 'f'], ['b', 'd', 'f']]
Subsets for  ['d', 'f']  are  [[], ['d'], ['f'], ['d', 'f']]
Subsets for  ['f']  are  [[], ['f']]

关于可维护性或可读性,这可能不切实际,但这令我震惊。感谢您分享智能解决方案!
lorey

1

空集是所有子集的一部分,则可以使用:

def subsets(iterable):
    for n in range(len(iterable) + 1):
        yield from combinations(iterable, n)

1

几乎所有这些答案都使用list而不是set来代替,这对我来说似乎有点作弊。因此,出于好奇,我尝试真正地制作一个简单的版本set并为其他“ Python新手”进行总结。

我发现在处理Python的set实现方面有很多奇怪之处。给我的主要惊喜是处理空集。这与Ruby的Set实现相反,在Ruby中,我可以简单地进行操作Set[Set[]]并获得一个Set包含一个empty的内容Set,因此我最初发现它有些混乱。

回顾powerset一下,在使用sets时,我遇到了两个问题:

  1. set()需要一个可迭代的,所以set(set())会返回,set() 因为空集的可迭代是空的(我猜:)
  2. 获得一组集合,set({set()})并且set.add(set)由于不可散列而无法工作set()

为了解决这两个问题,我使用了frozenset(),这意味着我没有得到我想要的东西(类型从字面上看set),而是利用了整体set界面。

def powerset(original_set):
  # below gives us a set with one empty set in it
  ps = set({frozenset()}) 
  for member in original_set:
    subset = set()
    for m in ps:
      # to be added into subset, needs to be
      # frozenset.union(set) so it's hashable
      subset.add(m.union(set([member]))
    ps = ps.union(subset)
  return ps

下面我们frozenset正确地得到2²(16)s作为输出:

In [1]: powerset(set([1,2,3,4]))
Out[2]:
{frozenset(),
 frozenset({3, 4}),
 frozenset({2}),
 frozenset({1, 4}),
 frozenset({3}),
 frozenset({2, 3}),
 frozenset({2, 3, 4}),
 frozenset({1, 2}),
 frozenset({2, 4}),
 frozenset({1}),
 frozenset({1, 2, 4}),
 frozenset({1, 3}),
 frozenset({1, 2, 3}),
 frozenset({4}),
 frozenset({1, 3, 4}),
 frozenset({1, 2, 3, 4})}

既然没有办法有一个setset,S在Python如果你想将这些frozensets转换setS,你必须回映射到listlist(map(set, powerset(set([1,2,3,4])))) )或修改上面。


1

也许这个问题越来越老了,但我希望我的代码能对某人有所帮助。

def powSet(set):
    if len(set) == 0:
       return [[]]
    return addtoAll(set[0],powSet(set[1:])) + powSet(set[1:])

def addtoAll(e, set):
   for c in set:
       c.append(e)
   return set

ew,递归!=)
étale-cohomology,

可能不是最有效的方法,但是看到递归方法总是很有趣的!
Lisandro Di Meo

1

使用powerset()包中的函数more_itertools

产生可迭代的所有可能子集

>>> list(powerset([1, 2, 3]))
[(), (1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]

如果要设置,请使用:

list(map(set, powerset(iterable)))

1
这么多的人在这里重新发明轮子,恕我直言,这是最好的答案,因为它可能已经存在于您的依赖项中,因为许多常用库(例如pytest)都需要它。libraries.io/pypi/more-itertools/dependents
lorey

1

递归获取所有子集。疯狂屁股一线

from typing import List

def subsets(xs: list) -> List[list]:
    return subsets(xs[1:]) + [x + [xs[0]] for x in subsets(xs[1:])] if xs else [[]]

基于Haskell解决方案

subsets :: [a] -> [[a]]
subsets [] = [[]]
subsets (x:xs) = map (x:) (subsets xs) ++ subsets xs

NameError: name 'List' is not defined
4LegsDrivenCat

@ 4LegsDrivenCat我已经添加了List进口
帕维尔·鲁宾

1
def findsubsets(s, n): 
    return list(itertools.combinations(s, n)) 

def allsubsets(s) :
    a = []
    for x in range(1,len(s)+1):
        a.append(map(set,findsubsets(s,x)))      
    return a

仅代码的答案被认为是低质量的:确保提供解释代码的作用以及如何解决问题。如果您可以在帖子中添加更多信息,将对询问者和将来的读者都有帮助。请参阅解释完全基于代码的答案
Calos

1

您可以这样做:

def powerset(x):
    m=[]
    if not x:
        m.append(x)
    else:
        A = x[0]
        B = x[1:]
        for z in powerset(B):
            m.append(z)
            r = [A] + z
            m.append(r)
    return m

print(powerset([1, 2, 3, 4]))

输出:

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

1
可能我建议在发布代码解决方案时,要足够友好地详细说明代码在做什么以及为什么使用这种方法来解决问题。新的编码人员不应只看代码块并复制/粘贴它,而不必确切知道代码在做什么以及为什么。感谢并欢迎您使用Stackoverflow。
Yokai

一个非常令人印象深刻且递归的答案。
约翰

1

我知道这为时已晚

已经有许多其他解决方案,但仍然...

def power_set(lst):
    pw_set = [[]]

    for i in range(0,len(lst)):
        for j in range(0,len(pw_set)):
            ele = pw_set[j].copy()
            ele = ele + [lst[i]]
            pw_set = pw_set + [ele]

    return pw_set

0

这很疯狂,因为这些答案均未提供实际的Python集的返回值。这是一个凌乱的实现,它将提供实际上是Python的powerset set

test_set = set(['yo', 'whatup', 'money'])
def powerset( base_set ):
    """ modified from pydoc's itertools recipe shown above"""
    from itertools import chain, combinations
    base_list = list( base_set )
    combo_list = [ combinations(base_list, r) for r in range(len(base_set)+1) ]

    powerset = set([])
    for ll in combo_list:
        list_of_frozensets = list( map( frozenset, map( list, ll ) ) ) 
        set_of_frozensets = set( list_of_frozensets )
        powerset = powerset.union( set_of_frozensets )

    return powerset

print powerset( test_set )
# >>> set([ frozenset(['money','whatup']), frozenset(['money','whatup','yo']), 
#        frozenset(['whatup']), frozenset(['whatup','yo']), frozenset(['yo']),
#        frozenset(['money','yo']), frozenset(['money']), frozenset([]) ])

不过,我希望看到更好的实现。


很好,但是OP希望有一组集合作为输出,因此(在Python 3中)可以做到[*map(set, chain.from_iterable(combinations(s, r) for r in range(len(s)+1)))];您map可以根据需要frozenset使用arg的功能。
下午18年

0

这是我利用组合但仅使用内置功能的快速实现。

def powerSet(array):
    length = str(len(array))
    formatter = '{:0' + length + 'b}'
    combinations = []
    for i in xrange(2**int(length)):
        combinations.append(formatter.format(i))
    sets = set()
    currentSet = []
    for combo in combinations:
        for i,val in enumerate(combo):
            if val=='1':
                currentSet.append(array[i])
        sets.add(tuple(sorted(currentSet)))
        currentSet = []
    return sets

0

范围n中的所有子集均已设置:

n = int(input())
l = [i for i in range (1, n + 1)]

for number in range(2 ** n) :
    binary = bin(number)[: 1 : -1]
    subset = [l[i] for i in range(len(binary)) if binary[i] == "1"]
    print(set(sorted(subset)) if number > 0 else "{}")

0
import math    
def printPowerSet(set,set_size): 
    pow_set_size =int(math.pow(2, set_size))
    for counter in range(pow_set_size):
    for j in range(set_size):  
        if((counter & (1 << j)) > 0):
            print(set[j], end = "")
    print("")
set = ['a', 'b', 'c']
printPowerSet(set,3)

0

我在《发现计算机科学:跨学科问题,原理和Python编程。2015年版》这本书中看到了一个问题的变体。在练习10.2.11中,输入只是一个整数,而输出应为幂集。这是我的递归解决方案(除了基本的python3,不使用其他任何东西)

def powerSetR(n):
    assert n >= 0
    if n == 0:
        return [[]]
    else:
        input_set = list(range(1, n+1)) # [1,2,...n]
        main_subset = [ ]
        for small_subset in powerSetR(n-1):
            main_subset += [small_subset]
            main_subset += [ [input_set[-1]] + small_subset]
        return main_subset

superset = powerSetR(4)
print(superset)       
print("Number of sublists:", len(superset))

输出是

[[],[4],[3],[4、3],[2],[4、2],[3、2],[4、3、2],[1],[4、1 ],[3、1],[4、3、1],[2、1],[4、2、1],[3、2、1],[4、3、2、1]]的数量子列表:16


0

我没有遇到过该more_itertools.powerset功能,建议使用它。我还建议不要使用的默认输出顺序itertools.combinations,通常是希望最小化位置之间的距离,并对位置之间距离较短的项目子集进行排序,使其高于/之间距离更大的项目。

itertools食谱页面显示它使用chain.from_iterable

  • 请注意,r这里与二项式系数的下部的标准符号匹配,s通常n在数学课本和计算器中称为“ n选择r”
def powerset(iterable):
    "powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"
    s = list(iterable)
    return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))

这里的其他示例[1,2,3,4]以2个元组以“字典顺序”的顺序列出(当我们将数字打印为整数时)给出的幂集。如果我在旁边写上数字之间的距离(即差),它表明了我的观点:

121
132
143
231
242
341

子集的正确顺序应该是首先“耗尽”最小距离的顺序,如下所示:

121
231
341
132
242
143

在这里使用数字会使此顺序看起来“错误”,但是考虑一下字母,["a","b","c","d"]这很清楚为什么对于按此顺序获得幂集可能很有​​用:

ab ⇒ 1
bc ⇒ 1
cd ⇒ 1
ac ⇒ 2
bd ⇒ 2
ad ⇒ 3

对于更多项目,此效果更加明显,就我的目的而言,它使能够有意义地描述Powerset的索引范围之间有所不同。

(关于组合代码中算法的输出顺序,有很多关于格雷码等的文章,我不认为这是附带问题)。

我实际上只是编写了一个相当复杂的程序,该程序使用此快速整数分区代码以正确的顺序输出值,但是随后我发现more_itertools.powerset并且对于大多数使用方法而言,仅使用该函数就可以了,就像这样:

from more_itertools import powerset
from numpy import ediff1d

def ps_sorter(tup):
    l = len(tup)
    d = ediff1d(tup).tolist()
    return l, d

ps = powerset([1,2,3,4])

ps = sorted(ps, key=ps_sorter)

for x in ps:
    print(x)

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

我写了一些更复杂的代码,这将很好地打印幂(见回购了漂亮的印刷,我这里不包括的功能:print_partitionsprint_partitions_by_length,和pprint_tuple)。

这一切都非常简单,但是如果您想要一些可以直接访问不同级别的Powerset的代码,它可能仍然有用:

from itertools import permutations as permute
from numpy import cumsum

# http://jeromekelleher.net/generating-integer-partitions.html
# via
# /programming/10035752/elegant-python-code-for-integer-partitioning#comment25080713_10036764

def asc_int_partitions(n):
    a = [0 for i in range(n + 1)]
    k = 1
    y = n - 1
    while k != 0:
        x = a[k - 1] + 1
        k -= 1
        while 2 * x <= y:
            a[k] = x
            y -= x
            k += 1
        l = k + 1
        while x <= y:
            a[k] = x
            a[l] = y
            yield tuple(a[:k + 2])
            x += 1
            y -= 1
        a[k] = x + y
        y = x + y - 1
        yield tuple(a[:k + 1])

# https://stackoverflow.com/a/6285330/2668831
def uniquely_permute(iterable, enforce_sort=False, r=None):
    previous = tuple()
    if enforce_sort: # potential waste of effort (default: False)
        iterable = sorted(iterable)
    for p in permute(iterable, r):
        if p > previous:
            previous = p
            yield p

def sum_min(p):
    return sum(p), min(p)

def partitions_by_length(max_n, sorting=True, permuting=False):
    partition_dict = {0: ()}
    for n in range(1,max_n+1):
        partition_dict.setdefault(n, [])
        partitions = list(asc_int_partitions(n))
        for p in partitions:
            if permuting:
                perms = uniquely_permute(p)
                for perm in perms:
                    partition_dict.get(len(p)).append(perm)
            else:
                partition_dict.get(len(p)).append(p)
    if not sorting:
        return partition_dict
    for k in partition_dict:
        partition_dict.update({k: sorted(partition_dict.get(k), key=sum_min)})
    return partition_dict

def print_partitions_by_length(max_n, sorting=True, permuting=True):
    partition_dict = partitions_by_length(max_n, sorting=sorting, permuting=permuting)
    for k in partition_dict:
        if k == 0:
            print(tuple(partition_dict.get(k)), end="")
        for p in partition_dict.get(k):
            print(pprint_tuple(p), end=" ")
        print()
    return

def generate_powerset(items, subset_handler=tuple, verbose=False):
    """
    Generate the powerset of an iterable `items`.

    Handling of the elements of the iterable is by whichever function is passed as
    `subset_handler`, which must be able to handle the `None` value for the
    empty set. The function `string_handler` will join the elements of the subset
    with the empty string (useful when `items` is an iterable of `str` variables).
    """
    ps = {0: [subset_handler()]}
    n = len(items)
    p_dict = partitions_by_length(n-1, sorting=True, permuting=True)
    for p_len, parts in p_dict.items():
        ps.setdefault(p_len, [])
        if p_len == 0:
            # singletons
            for offset in range(n):
                subset = subset_handler([items[offset]])
                if verbose:
                    if offset > 0:
                        print(end=" ")
                    if offset == n - 1:
                        print(subset, end="\n")
                    else:
                        print(subset, end=",")
                ps.get(p_len).append(subset)
        for pcount, partition in enumerate(parts):
            distance = sum(partition)
            indices = (cumsum(partition)).tolist()
            for offset in range(n - distance):
                subset = subset_handler([items[offset]] + [items[offset:][i] for i in indices])
                if verbose:
                    if offset > 0:
                        print(end=" ")
                    if offset == n - distance - 1:
                        print(subset, end="\n")
                    else:
                        print(subset, end=",")
                ps.get(p_len).append(subset)
        if verbose and p_len < n-1:
            print()
    return ps

作为示例,我编写了一个CLI演示程序,该程序将字符串作为命令行参数:

python string_powerset.py abcdef

a, b, c, d, e, f

ab, bc, cd, de, ef
ac, bd, ce, df
ad, be, cf
ae, bf
af

abc, bcd, cde, def
abd, bce, cdf
acd, bde, cef
abe, bcf
ade, bef
ace, bdf
abf
aef
acf
adf

abcd, bcde, cdef
abce, bcdf
abde, bcef
acde, bdef
abcf
abef
adef
abdf
acdf
acef

abcde, bcdef
abcdf
abcef
abdef
acdef

abcdef

0

如果您想要任何特定长度的子集,可以这样操作:

from itertools import combinations
someSet = {0, 1, 2, 3}
([x for i in range(len(someSet)+1) for x in combinations(someSet,i)])

通常,对于任意长度的子集,您可以修改范围偏差。输出是

[(),(0,),(1,),(2,),(3,),(0,1),(0,2),(0,3),(1,2),(1 ,3),(2,3),(0,1,2),(0,1,3),(0,2,3),(1,2,3),(0,1,2,3 )]


-1
def powerset(some_set):
    res = [(a,b) for a in some_set for b in some_set]
    return res

6
尽管此代码可以回答问题,但提供有关此代码为何和/或如何回答问题的其他上下文,可以提高其长期价值。考虑阅读“如何回答”编辑您的答案以改善答案。
blurfus

2
@blurfus始终是一个好习惯,但是当您用另外28个答案回答十年的问题时,这一点尤其重要。为什么比接受的答案有所改进?其他答案没有提供的答案是什么?
杰里米·卡尼
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.