Étant donné un ensemble
{0, 1, 2, 3}
Comment puis-je 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}]
La itertools
page Python a exactement une powerset
recette pour cela:
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))
Production:
>>> 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' range
instruction range(1, len(s)+1)
pour éviter une combinaison de longueur 0.
s = list(iterable)
nécessaire?__len__
implémentés essayezpowerset((n for n in range(3)))
sans l'encapsulation de la liste.powerset(range(3))
fonctionnerait bien même sanss = list(iterable)
.Voici plus de code pour un PowerSet. Ceci 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 s'applique 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 longueur 0 ", sauf dans mon cas, vous changez
for i in range(1 << x)
enfor i in range(1, 1 << x)
.En revenant à cela des 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 puis le code de test ressemblerait à ceci, disons:
print(list(powerset([4, 5, 6])))
L'utilisation
yield
signifie que vous n'avez pas besoin de calculer tous les résultats dans une seule mémoire. Le précalcul des masques en dehors de la boucle principale est supposé être une optimisation intéressante.la source
Si vous cherchez une réponse rapide, je viens de chercher "python power set" sur google et je suis venu avec 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
Cela 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]]
la source
[[][]]
, pour corriger cela, séparer simplement les cas de vérification de la longueurif len(seq) == 0: yield [] elif len(seq) == 1: yield seq yield []
def powerset(lst): return reduce(lambda result, x: result + [subset + [x] for subset in result], lst, [[]])
la source
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
la source
TL; DR (aller directement à Simplification)
Je sais que j'ai déjà ajouté une réponse, mais j'aime vraiment ma nouvelle implémentation. Je prends un ensemble comme entrée, mais il pourrait en fait être n'importe quel itérable, et je renvoie un ensemble d'ensembles qui est l'ensemble de puissance de l'entrée. J'aime cette approche car elle est plus alignée sur la définition mathématique de l' ensemble de puissance ( ensemble de tous les sous-ensembles ).
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
Si vous voulez exactement le résultat que vous avez publié dans votre réponse, utilisez ceci:
>>> [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}]
Explication
On sait que le nombre d'éléments de l'ensemble de puissance est
2 ** len(A)
, de sorte que cela pourrait être clairement vu dans lafor
boucle.J'ai besoin de convertir l'entrée (idéalement un ensemble) en une liste car un ensemble est une structure de données d'éléments uniques non ordonnés, et l'ordre sera crucial pour générer les sous-ensembles.
selector
est la clé de cet algorithme. Notez qu'ilselector
a la même longueur que l'ensemble d'entrée, et pour rendre cela possible, il utilise une f-string avec un remplissage. Fondamentalement, cela me permet de sélectionner les éléments qui seront ajoutés à chaque sous-ensemble à chaque itération. Disons que le jeu d'entrées a 3 éléments{0, 1, 2}
, donc le sélecteur prendra des valeurs comprises entre 0 et 7 (inclus), qui en binaire sont:000 # 0 001 # 1 010 # 2 011 # 3 100 # 4 101 # 5 110 # 6 111 # 7
Ainsi, chaque bit pourrait servir d'indicateur si un élément de l'ensemble d'origine doit être ajouté ou non. Regardez les nombres binaires, et pensez simplement à chaque nombre comme un élément du super ensemble dans lequel
1
signifie qu'un élément à l'indexj
doit être ajouté et0
que cet élément ne doit pas être ajouté.J'utilise une compréhension d'ensemble pour générer un sous-ensemble à chaque itération, et je convertis ce sous-ensemble en un
frozenset
afin que je puisse l'ajouter àps
(ensemble de puissance). Sinon, je ne pourrai pas l'ajouter car un ensemble en Python se compose uniquement d'objets immuables.Simplification
Vous pouvez simplifier le code en utilisant certaines compréhensions python, afin de pouvoir vous débarrasser de ces boucles for. Vous pouvez également utiliser
zip
pour éviter d'utiliser l'j
index et le code se terminera comme suit: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) }
C'est ça. Ce que j'aime de cet algorithme, c'est qu'il est plus clair et plus intuitif que d'autres car il semble assez magique de s'appuyer sur
itertools
même s'il fonctionne comme prévu.la source
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])
rendement
[[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]]
la source
power_set
) dans la boucle qu'elle régit est une pratique très discutable. Par exemple, supposons que vous avez écrit ceci à la place du code de variable modification proposée:power_set += [list(sub_set)+[elem]]
. Ensuite, la boucle ne se termine pas.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_powerset(remaining_list): subsets.append(partial_subset) subsets.append(partial_subset[:] + [first_element]) return subsets
Une autre façon de générer l'ensemble de puissance est de générer tous les nombres binaires qui ont des
n
bits. En tant que puissance définie, la quantité de nombre avecn
chiffres est2 ^ n
. Le principe de cet algorithme est qu'un élément peut être présent ou non dans un sous-ensemble car un chiffre binaire peut être 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.2x Introduction à la pensée computationnelle et à la science des données, et je considère que c'est l'un des algorithmes les plus faciles à comprendre que j'ai vus.
la source
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 resultats
Tous les ensembles de longueur 0
[()]
Tous les ensembles de longueur 1
[('x',), ('y',), ('z',)]
Tous les ensembles de longueur 2
[('x', 'y'), ('x', 'z'), ('y', 'z')]
Tous les ensembles de longueur 3
[('x', 'y', 'z')]
Pour plus d'informations, consultez la documentation itertools , ainsi que l'entrée wikipedia sur les ensembles d'alimentation
la source
Juste un rafraîchissement rapide de l'ensemble de puissance!
Voici une autre façon de trouver l'ensemble de puissance:
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]))
crédit total à la source
la source
Avec un ensemble vide, qui fait partie de tous les sous-ensembles, vous pouvez utiliser:
def subsets(iterable): for n in range(len(iterable) + 1): yield from combinations(iterable, n)
la source
Cela peut être fait très naturellement avec
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}
la source
Un moyen simple serait d'exploiter la représentation interne des nombres entiers sous l'arithmétique du complément à 2.
La représentation binaire des nombres entiers est {000, 001, 010, 011, 100, 101, 110, 111} pour les nombres allant de 0 à 7. Pour une valeur de compteur entière, en considérant 1 comme inclusion de l'élément correspondant dans la collection et «0» comme exclusion, nous pouvons générer des sous-ensembles basés sur la séquence de comptage. Les nombres doivent être générés de
0
àpow(2,n) -1
où n est la longueur du tableau, c'est-à-dire le nombre de bits en représentation binaire.Une fonction de générateur de sous-ensemble simple basée sur elle peut être écrite comme ci-dessous. Il repose essentiellement
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
et puis il peut être utilisé comme
def get_subsets(array): powerset = [] for i in subsets(array): powerser.append(i) return powerset
Essai
Ajout de suivi dans un fichier local
if __name__ == '__main__': sample = ['b', 'd', 'f'] for i in range(len(sample)): print "Subsets for " , sample[i:], " are ", get_subsets(sample[i:])
donne la sortie suivante
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']]
la source
Presque toutes ces réponses utilisent
list
plutôt queset
, ce qui me semblait un peu une triche. Donc, par curiosité, j'ai essayé de faire une version simpleset
et de résumer pour les autres "nouveaux à Python".J'ai trouvé qu'il y avait quelques bizarreries dans le traitement de l' implémentation d'ensemble de Python . La principale surprise pour moi a été de manipuler des décors vides. Ceci est en contraste avec l' implémentation de Ruby's Set , où je peux simplement faire
Set[Set[]]
et obtenir unSet
contenant un videSet
, donc je l'ai trouvé au départ un peu déroutant.Pour revoir, en faisant
powerset
avecset
s, j'ai rencontré deux problèmes:set()
prend un itérable, doncset(set())
reviendraset()
car l'ensemble vide itérable est vide (duh je suppose :))set({set()})
etset.add(set)
ne fonctionnera pas carset()
n'est pas hachablePour résoudre les deux problèmes, j'ai utilisé
frozenset()
, ce qui signifie que je n'obtiens pas tout à fait ce que je veux (le type est littéralementset
), mais utilise l'set
interface globale .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
Ci-dessous, nous obtenons 2² (16)
frozenset
s correctement en sortie: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})}
Comme il n'y a aucun moyen d'avoir un
set
deset
s en Python, si vous voulez transformer cesfrozenset
s enset
s, vous devrez les mapper à nouveau dans unlist
(list(map(set, powerset(set([1,2,3,4]))))
) ou modifier ce qui précède.la source
Peut-être que la question vieillit, mais j'espère que mon code aidera quelqu'un.
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
la source
Utilisez la fonction
powerset()
du packagemore_itertools
.>>> list(powerset([1, 2, 3])) [(), (1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]
Si vous voulez des ensembles, utilisez:
la source
Obtenir tous les sous-ensembles avec récursivité. Une doublure folle
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 [[]]
Basé sur une solution Haskell
la source
NameError: name 'List' is not defined
List
importationdef 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
la source
Vous pouvez le faire comme ceci:
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]))
Production:
[[], [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]]
la source
Je sais que c'est trop tard
Il existe déjà beaucoup d'autres solutions mais quand même ...
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
la source
C'est sauvage car aucune de ces réponses ne fournit réellement le retour d'un ensemble Python réel. Voici une implémentation désordonnée qui donnera un ensemble de pouvoirs 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'adorerais voir une meilleure implémentation, cependant.
la source
[*map(set, chain.from_iterable(combinations(s, r) for r in range(len(s)+1)))]
; la fonction arg demap
peut êtrefrozenset
si vous préférez.Voici ma mise en œuvre rapide en utilisant des combinaisons mais en utilisant uniquement des éléments intégrés.
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
la source
Tous les sous-ensembles de la plage n tels que définis:
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 "{}")
la source
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)
la source
Une variante de la question, est un exercice que je vois sur le livre "Discovering Computer Science: Interdisciplinary Problems, Principles, and Python Programming. 2015 edition". Dans cet exercice 10.2.11, l'entrée est juste un nombre entier et la sortie doit être les ensembles de puissance. Voici ma solution récursive (n'utilisant rien d'autre que python3 de base)
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))
Et la sortie est
[[], [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]] Nombre de sous-listes: 16
la source
Je n'avais pas rencontré la
more_itertools.powerset
fonction et je recommanderais de l'utiliser. Je recommande également de ne pas utiliser l'ordre par défaut de la sortie deitertools.combinations
, souvent au lieu de cela, vous voulez minimiser la distance entre les positions et trier les sous-ensembles d'éléments avec une distance plus courte entre eux au-dessus / avant les éléments avec une plus grande distance entre eux.La
itertools
page des recettes montre qu'il utilisechain.from_iterable
r
ici correspond à la notation standard pour la partie inférieure d'un coefficient binomial , les
est généralement appelén
dans les textes de mathématiques et sur les calculatrices («n Choisissez 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))
Les autres exemples ici donnent la puissance de
[1,2,3,4]
de telle manière que les 2-tuples sont listés dans l'ordre "lexicographique" (lorsque nous imprimons les nombres sous forme d'entiers). Si j'écris la distance entre les nombres à côté (c'est-à-dire la différence), cela montre mon point:12 ⇒ 1 13 ⇒ 2 14 ⇒ 3 23 ⇒ 1 24 ⇒ 2 34 ⇒ 1
L'ordre correct pour les sous-ensembles doit être l'ordre qui `` épuise '' d'abord la distance minimale, comme ceci:
12 ⇒ 1 23 ⇒ 1 34 ⇒ 1 13 ⇒ 2 24 ⇒ 2 14 ⇒ 3
L'utilisation de nombres ici rend cet ordre `` faux '', mais considérez par exemple les lettres,
["a","b","c","d"]
il est plus clair pourquoi cela pourrait être utile pour obtenir l'ensemble de puissance dans cet ordre:ab ⇒ 1 bc ⇒ 1 cd ⇒ 1 ac ⇒ 2 bd ⇒ 2 ad ⇒ 3
Cet effet est plus prononcé avec plus d'éléments, et pour mes besoins, cela fait la différence entre être capable de décrire de manière significative les plages des index de l'ensemble de puissance.
(Il y a beaucoup d'écrit sur les codes Gray, etc. pour l'ordre de sortie des algorithmes en combinatoire, je ne le vois pas comme un problème secondaire).
En fait, je viens d'écrire un programme assez complexe qui utilisait ce code de partition d'entier rapide pour afficher les valeurs dans le bon ordre, mais j'ai ensuite découvert
more_itertools.powerset
et pour la plupart des utilisations, il est probablement bien d'utiliser cette fonction comme suit: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)
J'ai écrit un code plus impliqué qui imprimera le powerset bien (voir la prise en pension pour à peu les fonctions d' impression , je ne l' ai pas inclus ici:
print_partitions
,print_partitions_by_length
etpprint_tuple
).pset_partitions.py
Tout cela est assez simple, mais cela peut quand même être utile si vous voulez un code qui vous permettra d'accéder directement aux différents niveaux de l'ensemble de puissance:
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
À titre d'exemple, j'ai écrit un programme de démonstration CLI qui prend une chaîne comme argument de ligne de commande:
⇣
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
la source
Si vous voulez une longueur spécifique de sous-ensembles, vous pouvez le faire comme ceci:
from itertools import combinations someSet = {0, 1, 2, 3} ([x for i in range(len(someSet)+1) for x in combinations(someSet,i)])
Plus généralement, pour les sous-ensembles de longueur arbitraire, vous pouvez modifier l'arugment de plage. La sortie est
[(), (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 )]
la source
Dans Python 3.5 ou supérieur, vous pouvez utiliser l'
yield from
instruction avec itertools.combinations :def subsets(iterable): for n in range(len(iterable)): yield from combinations(iterable, n + 1)
la source
def powerset(some_set): res = [(a,b) for a in some_set for b in some_set] return res
la source