Gegeben ein Satz
{0, 1, 2, 3}
Wie kann ich die Teilmengen erzeugen:
[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}]
Die Python- itertools
Seite hat genau ein powerset
Rezept dafür:
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))
Ausgabe:
>>> 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')]
Wenn Ihnen dieses leere Tupel am Anfang nicht gefällt, können Sie die range
Anweisung einfach so ändern range(1, len(s)+1)
, dass eine Kombination mit 0 Längen vermieden wird.
s = list(iterable)
benötigt?__len__
implementiert werden müssen; Probieren Sie espowerset((n for n in range(3)))
ohne Listenumbruch aus.powerset(range(3))
würde auch ohnes = list(iterable)
gut funktionieren .Hier ist mehr Code für ein Powerset. Dies ist von Grund auf neu geschrieben:
Mark Rushakoffs Kommentar gilt hier: "Wenn Ihnen dieses leere Tupel am Anfang nicht gefällt, können Sie die Range-Anweisung einfach in range (1, len (s) +1) ändern, um eine Kombination mit 0 Längen zu vermeiden." ", außer in meinem Fall wechseln Sie
for i in range(1 << x)
zufor i in range(1, 1 << x)
.Wenn ich Jahre später darauf zurückkomme, würde ich es jetzt so schreiben:
Und dann würde der Testcode so aussehen, sagen wir:
Verwenden
yield
bedeutet, dass Sie nicht alle Ergebnisse in einem einzigen Speicherelement berechnen müssen. Die Vorberechnung der Masken außerhalb der Hauptschleife wird als lohnende Optimierung angesehen.quelle
Wenn Sie nach einer schnellen Antwort suchen, habe ich gerade bei Google nach "Python Power Set" gesucht und mir Folgendes ausgedacht: Python Power Set Generator
Hier ist ein Copy-Paste aus dem Code auf dieser Seite:
Dies kann folgendermaßen verwendet werden:
Jetzt ist r eine Liste aller gewünschten Elemente und kann sortiert und gedruckt werden:
quelle
[[][]]
, um zu beheben, dass nur die Fälle für die Längenprüfung getrennt werdenif len(seq) == 0: yield [] elif len(seq) == 1: yield seq yield []
quelle
Es gibt eine Verfeinerung des Powersets:
quelle
TL; DR (direkt zur Vereinfachung gehen)
Ich weiß, dass ich zuvor eine Antwort hinzugefügt habe, aber meine neue Implementierung gefällt mir sehr gut. Ich nehme einen Satz als Eingabe, aber es könnte tatsächlich jeder iterierbare sein, und ich gebe einen Satz von Sätzen zurück, der der Potenzsatz der Eingabe ist. Ich mag diesen Ansatz, weil er mehr mit der mathematischen Definition der Potenzmenge ( Menge aller Teilmengen ) übereinstimmt .
Wenn Sie genau die Ausgabe wünschen, die Sie in Ihrer Antwort gepostet haben, verwenden Sie Folgendes:
Erläuterung
Es ist bekannt, dass die Anzahl der Elemente des Leistungssatzes so ist
2 ** len(A)
, dass dies in derfor
Schleife deutlich zu sehen ist.Ich muss die Eingabe (idealerweise eine Menge) in eine Liste konvertieren, da eine Menge eine Datenstruktur aus eindeutigen ungeordneten Elementen enthält und die Reihenfolge für die Generierung der Teilmengen entscheidend ist.
selector
ist der Schlüssel in diesem Algorithmus. Beachten Sie, dassselector
es die gleiche Länge wie der Eingabesatz hat. Um dies zu ermöglichen, wird ein F-String mit Auffüllung verwendet. Grundsätzlich kann ich so die Elemente auswählen, die während jeder Iteration zu jeder Teilmenge hinzugefügt werden. Angenommen, der Eingabesatz besteht aus 3 Elementen{0, 1, 2}
, sodass der Selektor Werte zwischen 0 und 7 (einschließlich) annimmt, die binär sind:Jedes Bit könnte also als Indikator dienen, ob ein Element des ursprünglichen Satzes hinzugefügt werden soll oder nicht. Schauen Sie sich die Binärzahlen an und stellen Sie sich jede Zahl als ein Element der Supermenge vor, was
1
bedeutet, dass ein Element am Indexj
hinzugefügt werden sollte und0
dass dieses Element nicht hinzugefügt werden sollte.Ich verwende ein Mengenverständnis, um bei jeder Iteration eine Teilmenge zu generieren, und konvertiere diese Teilmenge in eine,
frozenset
damit ich sie hinzufügen kannps
(Potenzmenge). Andernfalls kann ich es nicht hinzufügen, da ein Satz in Python nur aus unveränderlichen Objekten besteht.Vereinfachung
Sie können den Code mithilfe einiger Python-Verständnisse vereinfachen, um diese für Schleifen zu entfernen. Sie können auch verwenden
zip
, um die Verwendung vonj
Index zu vermeiden. Der Code lautet dann wie folgt:Das ist es. Was ich an diesem Algorithmus mag, ist, dass er klarer und intuitiver ist als andere, weil es ziemlich magisch aussieht, sich darauf zu verlassen
itertools
, obwohl er wie erwartet funktioniert.quelle
Beispielsweise:
Ausbeute
quelle
power_set
) in der von ihr gesteuerten Schleife ist eine sehr fragwürdige Praxis. Angenommen, Sie haben dies anstelle des vorgeschlagenen variablenmodifizierenden Codes geschrieben :power_set += [list(sub_set)+[elem]]
. Dann endet die Schleife nicht.Ich habe den folgenden Algorithmus sehr klar und einfach gefunden:
Eine andere Möglichkeit, das Powerset zu generieren, besteht darin, alle Binärzahlen mit
n
Bits zu generieren . Alsn
Potenzsatz ist die Anzahl der Ziffern2 ^ n
. Das Prinzip dieses Algorithmus ist, dass ein Element in einer Teilmenge vorhanden sein kann oder nicht, da eine Binärziffer eins oder null sein kann, aber nicht beide.Ich habe beide Algorithmen gefunden, als ich MITx: 6.00.2x Einführung in Computational Thinking und Data Science genommen habe, und ich halte es für einen der am einfachsten zu verstehenden Algorithmen, die ich je gesehen habe.
quelle
Ich wollte nur die verständlichste Lösung anbieten, die Anti-Code-Golf-Version.
Die Ergebnisse
Alle Sätze der Länge 0
[()]
Alle Sätze der Länge 1
[('x',), ('y',), ('z',)]
Alle Sätze der Länge 2
[('x', 'y'), ('x', 'z'), ('y', 'z')]
Alle Sätze der Länge 3
[('x', 'y', 'z')]
Weitere Informationen finden Sie in den itertools-Dokumenten sowie im Wikipedia-Eintrag zu Power Sets
quelle
Nur eine schnelle Auffrischung des Netzes!
Hier ist eine andere Möglichkeit, die eingestellte Leistung zu finden:
volle Gutschrift zur Quelle
quelle
Mit einer leeren Menge, die Teil aller Teilmengen ist, können Sie Folgendes verwenden:
quelle
Ein einfacher Weg wäre, die interne Darstellung von ganzen Zahlen unter der Komplementarithmetik von 2 zu nutzen.
Die binäre Darstellung von ganzen Zahlen ist {000, 001, 010, 011, 100, 101, 110, 111} für Zahlen im Bereich von 0 bis 7. Bei einem ganzzahligen Zählerwert wird 1 als Einbeziehung des entsprechenden Elements in die Sammlung und '0' betrachtet. Als Ausschluss können wir Teilmengen basierend auf der Zählsequenz generieren. Zahlen müssen von bis erzeugt werden
0
,pow(2,n) -1
wobei n die Länge des Arrays ist, dh die Anzahl der Bits in binärer Darstellung.Eine darauf basierende einfache Teilmengengeneratorfunktion kann wie folgt geschrieben werden. Es beruht im Grunde
und dann kann es als verwendet werden
Testen
Hinzufügen von Folgendem in lokaler Datei
gibt folgende Ausgabe
quelle
Fast alle diese Antworten verwenden
list
eher alsset
, was sich für mich wie ein Betrug anfühlte. Aus Neugier habe ich versucht, eine einfache Version wirklich zu machenset
und für andere "Python-Neulinge" zusammenzufassen.Ich fand, dass es ein paar Kuriositäten im Umgang mit Pythons Set-Implementierung gibt . Die Hauptüberraschung für mich war der Umgang mit leeren Sets. Dies steht im Gegensatz zu Rubys Set-Implementierung , bei der ich einfach
Set[Set[]]
eineSet
enthaltende leer machen kannSet
, sodass ich sie anfangs etwas verwirrend fand.Zur Überprüfung, dabei
powerset
mitset
s, begegnete ich zwei Probleme:set()
nimmt eine iterable,set(set())
wird also zurückkehren,set()
weil die leere Menge iterable leer ist (duh ich denke :))set({set()})
undset.add(set)
wird nicht funktionieren, weilset()
nicht hashbar istUm beide Probleme zu lösen, habe ich davon Gebrauch gemacht
frozenset()
, was bedeutet, dass ich nicht ganz das bekomme, was ich will (Typ ist wörtlichset
), sondern das gesamteset
Interace benutze.Unten erhalten wir 2² (16)
frozenset
s korrekt als Ausgabe:Da es keine Möglichkeit gibt , eine haben ,
set
vonset
s in Python, wenn Sie diese aktivieren möchtenfrozenset
s inset
s, werden Sie sie in eine zur Karte zurück habenlist
(list(map(set, powerset(set([1,2,3,4]))))
) oder die oben zu ändern.quelle
Vielleicht wird die Frage alt, aber ich hoffe, mein Code hilft jemandem.
quelle
Verwenden Sie die Funktion
powerset()
aus dem Paketmore_itertools
.Wenn Sie Sets möchten, verwenden Sie:
quelle
Abrufen aller Teilmengen mit Rekursion. Verrückter Einzeiler
Basierend auf einer Haskell-Lösung
quelle
NameError: name 'List' is not defined
List
Import hinzugefügtquelle
Dies ist wild, da keine dieser Antworten tatsächlich die Rückgabe eines tatsächlichen Python-Sets liefert. Hier ist eine chaotische Implementierung, die ein Powerset liefert, das tatsächlich ein Python ist
set
.Ich würde jedoch gerne eine bessere Implementierung sehen.
quelle
[*map(set, chain.from_iterable(combinations(s, r) for r in range(len(s)+1)))]
; Die Funktion arg vonmap
kann sein,frozenset
wenn Sie es vorziehen.Hier ist meine schnelle Implementierung, bei der Kombinationen verwendet werden, aber nur integrierte Funktionen verwendet werden.
quelle
Alle Teilmengen im Bereich n wie eingestellt:
quelle
quelle
Eine Variation der Frage ist eine Übung, die ich im Buch "Discovering Computer Science: Interdisziplinäre Probleme, Prinzipien und Python-Programmierung. Ausgabe 2015" sehe. In dieser Übung 10.2.11 ist die Eingabe nur eine Ganzzahl, und die Ausgabe sollte die Potenzsätze sein. Hier ist meine rekursive Lösung (ich verwende nichts anderes als Python3).
Und die Ausgabe ist
[[], [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]] Anzahl von Unterlisten: 16
quelle
Ich war nicht auf die
more_itertools.powerset
Funktion gestoßen und würde empfehlen, sie zu verwenden. Ich empfehle außerdem, nicht die Standardreihenfolge der Ausgabe von zu verwendenitertools.combinations
. Oft möchten Sie stattdessen den Abstand minimieren zwischen den Positionen und die Teilmengen von Elementen mit kürzerem Abstand über / vor den Elementen mit größerem Abstand zwischen ihnen sortieren.Die
itertools
Rezeptseite zeigt die Verwendungchain.from_iterable
r
hier mit der Standardnotation für den unteren Teil eines Binomialkoeffizienten übereinstimmt , dass
ist in der Regel bezeichnet alsn
in der Mathematik Texten und auf Rechner ( „n Wählen Sie r“)Die anderen Beispiele hier geben das Powerset von
[1,2,3,4]
so an, dass die 2-Tupel in "lexikografischer" Reihenfolge aufgelistet sind (wenn wir die Zahlen als ganze Zahlen drucken). Wenn ich den Abstand zwischen den Zahlen daneben schreibe (dh den Unterschied), zeigt dies meinen Punkt:Die richtige Reihenfolge für Teilmengen sollte die Reihenfolge sein, in der der minimale Abstand zuerst "erschöpft" wird, wie folgt:
Wenn Sie hier Zahlen verwenden, sieht diese Reihenfolge "falsch" aus. Beachten Sie jedoch beispielsweise die Buchstaben
["a","b","c","d"]
Es ist klarer, warum dies nützlich sein kann, um das Powerset in dieser Reihenfolge zu erhalten:Dieser Effekt ist bei mehr Elementen stärker ausgeprägt und macht für meine Zwecke den Unterschied zwischen der Möglichkeit, die Bereiche der Indizes des Powersets sinnvoll zu beschreiben.
(Es ist viel geschrieben Für die Ausgabereihenfolge von Algorithmen in der Kombinatorik Gray-Codes usw. , ich sehe dies nicht als Nebenproblem).
Ich habe gerade ein ziemlich kompliziertes Programm geschrieben, das diesen schnellen ganzzahligen Partitionscode verwendet hat, um die Werte in der richtigen Reihenfolge auszugeben, aber dann habe ich festgestellt, dass es
more_itertools.powerset
für die meisten Anwendungen wahrscheinlich in Ordnung ist, diese Funktion einfach so zu verwenden:⇣
Ich schrieb etwas mehr beteiligt Code, der sehr schön die Powerset gedruckt wird (siehe die repo für ziemlich Funktionen Drucken ich hier nicht enthalten habe:
print_partitions
,print_partitions_by_length
, undpprint_tuple
).pset_partitions.py
Dies ist alles ziemlich einfach, kann aber dennoch nützlich sein, wenn Sie Code benötigen, mit dem Sie direkt auf die verschiedenen Ebenen des Powersets zugreifen können:
Als Beispiel habe ich ein CLI-Demoprogramm geschrieben, das eine Zeichenfolge als Befehlszeilenargument verwendet:
⇣
quelle
Wenn Sie eine bestimmte Länge von Teilmengen wünschen, können Sie dies folgendermaßen tun:
Allgemeiner können Sie für Teilmengen mit beliebiger Länge das Bereichsarugment ändern. Die Ausgabe ist
[(), (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 )]
quelle
Sie können es so machen:
Ausgabe:
quelle
In Python 3.5 oder höher können Sie die
yield from
Anweisung zusammen mit itertools.combinations verwenden :quelle