Hier ist ein fauler Einzeiler, der ebenfalls itertools verwendet:
from itertools import compress, product
def combinations(items):
return ( set(compress(items,mask)) for mask in product(*[[0,1]]*len(items)) )
# alternative: ...in product([0,1], repeat=len(items)) )
Der Grundgedanke hinter dieser Antwort: Es gibt 2^N Kombinationen - das entspricht der Anzahl der binären Zeichenfolgen der Länge N. Für jede binäre Zeichenfolge werden alle Elemente ausgewählt, die einer "1" entsprechen.
items=abc * mask=###
|
V
000 ->
001 -> c
010 -> b
011 -> bc
100 -> a
101 -> a c
110 -> ab
111 -> abc
Zu beachtende Punkte:
- Dies setzt voraus, dass Sie Folgendes aufrufen können
len(...)
auf items
(Abhilfe: wenn items
so etwas wie eine Iterable wie ein Generator ist, wandeln Sie sie zuerst in eine Liste um mit items=list(_itemsArg)
)
- Dies erfordert, dass die Reihenfolge der Iteration auf
items
nicht zufällig ist (Abhilfe: nicht verrückt sein)
- Dies setzt voraus, dass die Gegenstände eindeutig sind, andernfalls
{2,2,1}
y {2,1,1}
kollabieren beide zu {2,1}
(Umgehung: Verwendung von collections.Counter
als sofortiger Ersatz für set
; es ist im Grunde ein Multiset... obwohl Sie später vielleicht tuple(sorted(Counter(...).elements()))
wenn Sie es als Hashwert benötigen)
Demo
>>> list(combinations(range(4)))
[set(), {3}, {2}, {2, 3}, {1}, {1, 3}, {1, 2}, {1, 2, 3}, {0}, {0, 3}, {0, 2}, {0, 2, 3}, {0, 1}, {0, 1, 3}, {0, 1, 2}, {0, 1, 2, 3}]
>>> list(combinations('abcd'))
[set(), {'d'}, {'c'}, {'c', 'd'}, {'b'}, {'b', 'd'}, {'c', 'b'}, {'c', 'b', 'd'}, {'a'}, {'a', 'd'}, {'a', 'c'}, {'a', 'c', 'd'}, {'a', 'b'}, {'a', 'b', 'd'}, {'a', 'c', 'b'}, {'a', 'c', 'b', 'd'}]
18 Stimmen
Die Leserinnen und Leser sollten beachten, dass unabhängig davon, ob es sich bei den Listenpunkten um einzigartig ist eine extrem wichtige Überlegung, da viele Algorithmen dann einige Teilmengen überzählen (z. B. 'abccc' -> ['', 'a', 'b', 'c', 'c', 'c', 'ac', 'ac', 'ac', ...]. Eine einfache Abhilfe besteht darin, alle Elemente in eine Menge zu schieben vor ihre Permutationen zu erhalten.
0 Stimmen
@ninjagecko Die Verwendung der Set-Bibliothek ist nicht effizient, da sie im besten Fall O(n) ist. Das Hinzufügen von n Funktionen zu einer Menge ist also tatsächlich O(n^2)!
3 Stimmen
Nach sorgfältiger Lektüre der Frage scheint es so, als ob der Fragesteller nach dem PowerSet seiner Liste von 15 Zahlen, nicht alle Kombinationen. Ich glaube, das ist der Grund, warum die Antworten so unterschiedlich ausfallen.
0 Stimmen
@Scott Biggs: Sind Sie sicher, dass Sie sich hier auf Python beziehen? Das Einfügen von Mengen und das Nachschlagen sind O(1) im durchschnittlichen Fall. Sie sind wie Wörterbücher. Sie verwenden Hashing. Python hat keine spezielle Mengenbibliothek (sie ist in der Standardbibliothek enthalten). Wir fügen hier Zahlen ein, keine Funktionen. (Es wäre immer noch ineffizient, O(2^n) Speicher zu verwenden; die richtige Lösung für Leute, die eher Kombinationen als die Potenzmenge wollen, ist eine einfache rekursive Implementierung, oder
product
, usw.)0 Stimmen
Siehe auch stackoverflow.com/questions/10342939/ .