Ich schreibe ein Programm in Python und habe festgestellt, dass ein Problem, das ich lösen muss, es erfordert, dass ich bei einer Menge S
von n
Elementen (| S | = n) eine Funktion für alle möglichen Teilmengen einer bestimmten Reihenfolge m
(dh mit m) teste Anzahl der Elemente). Verwenden Sie die Antwort, um eine Teillösung zu erstellen, und versuchen Sie es dann erneut mit der nächsten Reihenfolge m = m + 1, bis m = n.
Ich bin auf dem Weg, eine Lösung des Formulars zu schreiben:
def findsubsets(S, m):
subsets = set([])
...
return subsets
Da ich Python kannte, erwartete ich, dass es bereits eine Lösung geben würde.
Was ist der beste Weg, um dies zu erreichen?
scipy.misc.comb(S, m)
gibt die Anzahl der Teilmengen an, die Sie erhalten. Sie sollten eventuell eine Überprüfung durchführen, bevor Sie Ihren Code ausführen, da die Anzahl der m-großen Teilmengen von S sehr schnell sehr groß wird.Antworten:
itertools.combinations ist dein Freund, wenn du Python 2.6 oder höher hast. Überprüfen Sie andernfalls den Link auf eine Implementierung einer äquivalenten Funktion.
import itertools def findsubsets(S,m): return set(itertools.combinations(S, m))
S: Die Menge, für die Sie Teilmengen suchen möchten
m: Die Anzahl der Elemente in der Teilmenge
quelle
Verwenden der kanonischen Funktion, um das Powerset von der Rezeptseite von itertools abzurufen :
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))
Verwendet wie:
>>> list(powerset("abc")) [(), ('a',), ('b',), ('c',), ('a', 'b'), ('a', 'c'), ('b', 'c'), ('a', 'b', 'c')] >>> list(powerset(set([1,2,3]))) [(), (1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]
Wenn Sie möchten, können Sie Sets zuordnen, damit Sie Union, Kreuzung usw. verwenden können.
>>> map(set, powerset(set([1,2,3]))) [set([]), set([1]), set([2]), set([3]), set([1, 2]), set([1, 3]), set([2, 3]), set([1, 2, 3])] >>> reduce(lambda x,y: x.union(y), map(set, powerset(set([1,2,3])))) set([1, 2, 3])
quelle
Hier ist eine Funktion, die Ihnen alle Teilmengen der ganzen Zahlen [0..n] gibt, nicht nur die Teilmengen einer bestimmten Länge:
from itertools import combinations, chain def allsubsets(n): return list(chain(*[combinations(range(n), ni) for ni in range(n+1)]))
also zB
>>> allsubsets(3) [(), (0,), (1,), (2,), (0, 1), (0, 2), (1, 2), (0, 1, 2)]
quelle
chain.from_iterable
anstelle der Sternexpansion einen möglicherweise sehr langen Satz. Und was ist der Punkt , um die Kombinationen in eine Liste von Iterieren ([ ... ]
), Stern-Erweiterung Verkettungs in ein Iterator (chain
) und dann in eine Liste drehen wieder ? PS. Ein besseres Rezept finden Sie in deritertools
Dokumentation und in einer anderen (späteren) Antwort hier.def
stattdessen ein.Hier ist ein guter Weg mit leicht verständlichem Algorithmus.
import copy nums = [2,3,4,5] subsets = [[]] for n in nums: prev = copy.deepcopy(subsets) [k.append(n) for k in subsets] subsets.extend(prev) print(subsets) print(len(subsets)) # [[2, 3, 4, 5], [3, 4, 5], [2, 4, 5], [4, 5], [2, 3, 5], [3, 5], [2, 5], [5], # [2, 3, 4], [3, 4], [2, 4], [4], [2, 3], [3], [2], []] # 16 (2^len(nums))
quelle
k.append(n)
stattk.extend(n)
Hier ist ein Pseudocode: Sie können dieselben rekursiven Aufrufe abschneiden, indem Sie die Werte für jeden Anruf speichern und vor der rekursiven Anrufprüfung prüfen, ob der Aufrufwert bereits vorhanden ist.
Der folgende Algorithmus enthält alle Teilmengen mit Ausnahme der leeren Menge.
list * subsets(string s, list * v) { if(s.length() == 1) { list.add(s); return v; } else { list * temp = subsets(s[1 to length-1], v); int length = temp->size(); for(int i=0;i<length;i++) { temp.add(s[0]+temp[i]); } list.add(s[0]); return temp; } }
Wenn zum Beispiel s = "123" ist, lautet die Ausgabe:
1 2 3 12 13 23 123
quelle
Ohne zu verwenden
itertools
:In Python 3 können Sie
yield from
der Buit-In-set
Klasse eine Subset-Generator-Methode hinzufügen :class SetWithSubset(set): def subsets(self): s1 = [] s2 = list(self) def recfunc(i=0): if i == len(s2): yield frozenset(s1) else: yield from recfunc(i + 1) s1.append(s2[ i ]) yield from recfunc(i + 1) s1.pop() yield from recfunc()
Zum Beispiel funktioniert das folgende Snippet wie erwartet:
x = SetWithSubset({1,2,3,5,6}) {2,3} in x.subsets() # True set() in x.subsets() # True x in x.subsets() # True x|{7} in x.subsets() # False set([5,3]) in x.subsets() # True - better alternative: set([5,3]) < x len(x.subsets()) # 32
quelle
yield from
und mit einer algorithmischen Erklärung$ python -c "import itertools; a=[2,3,5,7,11]; print sum([list(itertools.combinations(a, i)) for i in range(len(a)+1)], [])" [(), (2,), (3,), (5,), (7,), (11,), (2, 3), (2, 5), (2, 7), (2, 11), (3, 5), (3, 7), (3, 11), (5, 7), (5, 11), (7, 11), (2, 3, 5), (2, 3, 7), (2, 3, 11), (2, 5, 7), (2, 5, 11), (2, 7, 11), (3, 5, 7), (3, 5, 11), (3, 7, 11), (5, 7, 11), (2, 3, 5, 7), (2, 3, 5, 11), (2, 3, 7, 11), (2, 5, 7, 11), (3, 5, 7, 11), (2, 3, 5, 7, 11)]
quelle
>>>Set = ["A", "B","C","D"] >>>n = 2 >>>Subsets=[[i for i,s in zip(Set, status) if int(s) ] for status in [(format(bit,'b').zfill(len(Set))) for bit in range(2**len(Set))] if sum(map(int,status)) == n] >>>Subsets [['C', 'D'], ['B', 'D'], ['B', 'C'], ['A', 'D'], ['A', 'C'], ['A', 'B']]
quelle
Eine andere Lösung mit Rekursion:
def subsets(nums: List[int]) -> List[List[int]]: n = len(nums) output = [[]] for num in nums: output += [curr + [num] for curr in output] return output
Ausgehend von einer leeren Teilmenge in der Ausgabeliste. Bei jedem Schritt berücksichtigen wir eine neue Ganzzahl und generieren aus den vorhandenen neue Teilmengen.
quelle