Holen Sie sich alle möglichen (2^N) Kombinationen der Elemente einer Liste beliebiger Länge

Lesezeit: 5 Minuten

Bens Benutzeravatar
Ben

Ich habe eine Liste mit 15 Nummern. Wie kann ich alle 32.768 Kombinationen dieser Zahlen erzeugen (dh eine beliebige Anzahl von Elementen in der ursprünglichen Reihenfolge)?

Ich dachte daran, die dezimalen Ganzzahlen 1–32768 zu durchlaufen und die binäre Darstellung jeder Zahl als Filter zu verwenden, um die entsprechenden Listenelemente auszuwählen. Gibt es einen besseren Weg, es zu tun?


Für Kombinationen einer bestimmten Länge, siehe Alle (n-choose-k)-Kombinationen der Länge n abrufen. Bitte verwenden Sie stattdessen diese Frage, um gegebenenfalls Duplikate zu schließen.

Wenn Sie Fragen zur Kombinatorik als Duplikate schließen, ist es sehr wichtig, darauf zu achten, welches OP eigentlich will, nicht die Wörter, die verwendet wurden, um das Problem zu beschreiben. Es kommt sehr häufig vor, dass Personen, die beispielsweise ein kartesisches Produkt wünschen (siehe So erhalten Sie das kartesische Produkt mehrerer Listen), nach “Kombinationen” fragen.

  • Leser sollten beachten, ob die Listenelemente sind einzigartig ist eine äußerst wichtige Überlegung, da viele Algorithmen dann einige Teilmengen überzählen (z. B. ‘abccc’ -> [”, ‘a’, ‘b’, ‘c’, ‘c’, ‘c’, ‘ac’, ‘ac’, ‘ac’, …]. Eine einfache Problemumgehung besteht darin, einfach alle Elemente in einen Satz zu schieben Vor bekommen ihre Permutationen.

    – Ninjagecko

    14. September 2015 um 0:23 Uhr

  • @ninjagecko Die Verwendung der Set-Bibliothek ist nicht effizient, da sie bestenfalls O (n) sind. Das Hinzufügen von n Funktionen zu einer Menge ist also tatsächlich O(n^2)!

    – SMBiggs

    11. Februar 2020 um 6:02 Uhr

  • Wenn man die Frage sorgfältig liest, scheint es, dass das OP nach der fragt PowerSet seiner Liste mit 15 Zahlen, nicht alle Kombinationen. Ich denke, das könnte der Grund sein, warum die Antworten überall sind.

    – SMBiggs

    11. Februar 2020 um 6:53 Uhr

  • @Scott Biggs: Bist du sicher, dass du hier über Python sprichst? Set-Einfügungen und Lookups sind O(1)-Durchschnittsfälle. Sie sind wie Wörterbücher. Sie verwenden Hashing. Python hat keine spezielle Set-Bibliothek (sie befindet sich in der Standardbibliothek). 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 Kombinationen statt des Powersets wollen, ist eine einfache rekursive Implementierung, oder productusw.)

    – Ninjagecko

    12. Februar 2020 um 9:36 Uhr

Benutzeravatar von James Brady
James Brady

Schau mal rein itertools.combinations:

itertools.combinations(iterable, r)

Gibt Untersequenzen der Länge r von Elementen aus der iterierbaren Eingabe zurück.

Kombinationen werden in lexikografischer Sortierreihenfolge ausgegeben. Wenn also die Eingabe-Iterable sortiert ist, werden die Kombinationstupel in sortierter Reihenfolge erzeugt.

Seit 2.6 sind Batterien enthalten!

  • Sie können einfach alles auflisten. list(itertools.combinations(iterable, r))

    – Silikon

    14. September 2017 um 12:23 Uhr

  • gibt es etwas, das nicht erforderlich ist rdh Kombinationen beliebig langer Teilfolgen von Elementen.

    – mlSchüler33

    23. Mai 2020 um 5:39 Uhr

  • Das ist sehr gut und hat mich darauf hingewiesen, was mein Problem wirklich gelöst hat, nämlich itertools.combination_with_replacement.

    – Benutzer3348949

    15. Oktober 2020 um 23:39 Uhr


  • die Funktion schreibt intertools.combinations_with_replacement

    – Al Martins

    3. September 2021 um 17:53 Uhr

  • Was ist der list() Umwandlung für in erster Linie?

    – AMC

    7. Dezember 2019 um 4:47 Uhr

  • @Alexander: Damit die Länge des Iterables bestimmt werden kann.

    – Martinau

    7. Dezember 2019 um 8:37 Uhr

  • …aber dies ist im Wesentlichen ein Refactoring von Dan H’s all_subsets Code, nur mit chain.from_iterable(x) anstatt chain(*x).

    – Karl Knechtel

    2. März um 0:26

Benutzeravatar von ninjagecko
Ninjagecko

Hier ist ein fauler Einzeiler, der auch 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)) )

Hauptidee hinter dieser Antwort: Es gibt 2 ^ N Kombinationen – genau wie die Anzahl der binären Zeichenfolgen der Länge N. Für jede binäre Zeichenfolge wählen Sie alle Elemente aus, die einer “1” entsprechen.

items=abc * mask=###
 |
 V
000 -> 
001 ->   c
010 ->  b
011 ->  bc
100 -> a
101 -> a c
110 -> ab
111 -> abc

Dinge, die man beachten muss:

  • Voraussetzung dafür ist, dass Sie anrufen können len(...) An items (Abhilfe: Wenn items ist so etwas wie ein Iterable wie ein Generator, wandeln Sie es zuerst in eine Liste um items=list(_itemsArg))
  • Dies erfordert, dass die Reihenfolge der Iteration an items ist nicht zufällig (Workaround: sei nicht verrückt)
  • Dies erfordert, dass die Artikel einzigartig sind, oder sonst {2,2,1} Und {2,1,1} werden beide zusammenbrechen {2,1} (Abhilfe: verwenden collections.Counter als Drop-In-Ersatz für set; Es ist im Grunde ein Multiset … obwohl Sie es möglicherweise später verwenden müssen tuple(sorted(Counter(...).elements())) wenn es hashbar sein soll)

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

Dies ist ein Ansatz, der sich leicht auf alle Programmiersprachen übertragen lässt, die Rekursion unterstützen (keine Itertools, kein Yield, kein Listenverständnis):

def combs(a):
    if len(a) == 0:
        return [[]]
    cs = []
    for c in combs(a[1:]):
        cs += [c, c+[a[0]]]
    return cs

>>> combs([1,2,3,4,5])
[[], [1], [2], [2, 1], [3], [3, 1], [3, 2], ..., [5, 4, 3, 2, 1]]

Benutzeravatar von darxtrix
darxtrix

Hier ist eine mit Rekursion:

>>> import copy
>>> def combinations(target,data):
...     for i in range(len(data)):
...         new_target = copy.copy(target)
...         new_data = copy.copy(data)
...         new_target.append(data[i])
...         new_data = data[i+1:]
...         print new_target
...         combinations(new_target,
...                      new_data)
...                      
... 
>>> target = []
>>> data = ['a','b','c','d']
>>> 
>>> combinations(target,data)
['a']
['a', 'b']
['a', 'b', 'c']
['a', 'b', 'c', 'd']
['a', 'b', 'd']
['a', 'c']
['a', 'c', 'd']
['a', 'd']
['b']
['b', 'c']
['b', 'c', 'd']
['b', 'd']
['c']
['c', 'd']
['d']

  • Kann dies geändert werden, um eine Liste von Listen zurückzugeben, anstatt sie zu drucken?

    – James Vickery

    9. November 2017 um 2:14 Uhr

  • @JamesVickery ja, Sie könnten entweder eine Liste außerhalb der Funktion erstellen und diese anhängen oder (besser) die Funktion zu einem Generator machen, sehen Sie sich das Schlüsselwort ‘yield’ an 🙂

    – Gefahrenkrähe

    12. November 2017 um 14:01 Uhr

  • new_data = copy.copy(data) – Diese Zeile ist meines Erachtens überflüssig, sie hat keinen Einfluss auf irgendetwas

    – Dmitri Fialkovskiy

    25. Oktober 2018 um 14:27 Uhr


1449060cookie-checkHolen Sie sich alle möglichen (2^N) Kombinationen der Elemente einer Liste beliebiger Länge

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy