Quelle est la bonne façon d'obtenir tous les sous-ensembles d'un ensemble? (powerset)

étant Donné un ensemble

{0, 1, 2, 3}

Quelle est la bonne façon de produire les sous-ensembles:

[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}]
37
demandé sur wim 2009-09-27 02:11:20

10 réponses

Le Python itertools page a exactement un powerset recette:

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))

sortie:

>>> 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')]

si vous n'aimez pas ce tuple vide au début, vous pouvez simplement changer l'énoncé range en range(1, len(s)+1) pour éviter une combinaison de 0 Longueur.

63
répondu Mark Rushakoff 2009-09-26 22:18:15

voici plus de code pour un groupe électrogène. C'est écrit à partir de zéro:

>>> 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]

le commentaire de Mark Rushakoff est applicable ici: "si vous n'aimez pas ce tuple vide au début, on."vous pouvez simplement changer l'instruction range En range(1, len(s)+1) pour éviter une combinaison de 0-length", sauf dans mon cas vous changez for i in range(1 << x) en for i in range(1, 1 << x) .


revenant à ces années plus tard, je l'écrirais maintenant comme ceci:

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]

et alors le code de test ressemblerait à ceci, dire:

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

en utilisant yield signifie que vous n'avez pas besoin de calculer tous les résultats dans une seule pièce de mémoire. Le précalcul des masques à l'extérieur de la boucle principale est supposé être une optimisation valable.

25
répondu hughdbrown 2016-12-20 22:44:23

si vous cherchez une réponse rapide, j'ai juste cherché "Python power set" sur google et j'ai trouvé ceci: Python Power Set Generator

voici un copier-coller du code de cette page:

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

ce qui peut être utilisé comme ceci:

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

maintenant R est une liste de tous les éléments que vous vouliez, et peut être triée et imprimée:

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]]
13
répondu Edan Maor 2009-09-26 22:21:05
def powerset(lst):
    return reduce(lambda result, x: result + [subset + [x] for subset in result],
                  lst, [[]])
8
répondu newacct 2009-09-26 22:54:12

Il y a un raffinement de 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
5
répondu Jingguo Yao 2013-09-29 13:43:39
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

par exemple:

get_power_set([1,2,3])
"151930920 le" rendement

[[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]]
3
répondu jmkg 2013-07-17 12:40:08

je voulais juste fournir la solution la plus compréhensible, la version anti code-golf.

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

les résultats

tous les jeux de longueur 0

[()]

tous les jeux de longueur 1

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

tous les jeux de longueur 2

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

tous les jeux de longueur 3

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

pour plus voir les docs itertools , aussi l'entrée Wikipédia sur power sets

1
répondu Gourneau 2016-03-21 01:59:22

C'est fou parce qu'aucune de ces réponses fournir le retour d'un véritable Python ensemble. Voici une implémentation désordonnée qui donnera un powerset qui est en fait un Python 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([]) ])

j'aimerais voir une meilleure implémentation.

0
répondu Мати Тернер 2013-04-11 06:57:48

Voici mon implémentation rapide en utilisant des combinaisons mais en n'utilisant que des built-ins.

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
répondu Daniel 2013-09-20 23:06:30

j'ai trouvé l'algorithme suivant très clair et simple:

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_all_subsets(remaining_list):
        subsets.append(partial_subset)
        subsets.append(partial_subset[:] + [first_element])

    return subsets

une autre façon de générer le groupe électrogène est de générer tous les nombres binaires qui ont des bits n . Comme un jeu de puissance la quantité de nombre avec n chiffres est 2 ^ n . Le principe de cet algorithme est qu'un élément peut être présent ou non dans un sous-ensemble comme un chiffre binaire pourrait être l'un ou zéro, mais pas les deux.

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

j'ai trouvé les deux algorithmes lorsque je prenais MITx: 6.00.2 X Introduction à la pensée computationnelle et la science des données, et je considère qu'il est l'un des algorithmes les plus faciles à comprendre que j'ai vu.

0
répondu lmiguelvargasf 2017-03-12 00:21:35