Wie erhalte ich alle möglichen Kombinationen der Elemente einer Liste?


420

Ich habe eine Liste mit 15 Zahlen und muss Code schreiben, der alle 32.768 Kombinationen dieser Zahlen erzeugt.

Ich habe einen Code (von Googling) gefunden, der anscheinend das tut, wonach ich suche, aber ich fand den Code ziemlich undurchsichtig und bin vorsichtig, ihn zu verwenden. Außerdem habe ich das Gefühl, dass es eine elegantere Lösung geben muss.

Das einzige, was mir einfällt, ist, einfach die Dezimalzahlen 1–32768 zu durchlaufen und diese in Binärzahlen umzuwandeln und die Binärdarstellung als Filter zu verwenden, um die entsprechenden Zahlen auszuwählen.

Kennt jemand einen besseren Weg? Verwenden Sie map()vielleicht?


9
Leser sollten beachten, dass es äußerst wichtig ist, ob die Listenelemente eindeutig sind, da viele Algorithmen dann eine Teilmenge überzählen (z. B. 'abccc' -> ['', 'a', 'b', 'c', 'c'). , 'c', 'ac', 'ac', 'ac', ...]. Eine einfache Problemumgehung besteht darin, alle Elemente in einem Satz zu verschieben, bevor ihre Permutationen
abgerufen werden

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

Nach sorgfältiger Lektüre der Frage scheint das OP nach dem PowerSet seiner Liste mit 15 Nummern zu fragen , nicht nach allen Kombinationen. Ich denke, das mag der Grund sein, warum die Antworten überall sind.
Scott Biggs

@ Scott Biggs: Bist du sicher, dass du hier über Python redest? Festgelegte Einfügungen und Suchvorgänge sind O (1) Durchschnittsfälle. Sie sind wie Wörterbücher. Sie verwenden Hashing. Python hat keine spezielle Set-Bibliothek (es ist 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 Personen, die Kombinationen anstelle des Powersets wünschen, ist eine einfache rekursive Implementierung productusw.)
ninjagecko

Antworten:


464

Schauen Sie sich itertools.combinations an :

itertools.combinations(iterable, r)

Rücklaufsequenzen von Elementen mit r Länge von der iterablen Eingabe zurückgeben.

Kombinationen werden in lexikografischer Sortierreihenfolge ausgegeben. Wenn die iterierbare Eingabe sortiert ist, werden die Kombinationstupel in sortierter Reihenfolge erstellt.

Seit 2.6 sind Batterien enthalten!


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

1
Gibt es etwas, das nicht benötigt wird r, dh Kombinationen von Längenuntersequenzen von Elementen.
mLstudent33

627

Diese Antwort hat einen Aspekt übersehen: Das OP hat nach ALLEN Kombinationen gefragt ... nicht nur nach Kombinationen der Länge "r".

Sie müssten also entweder alle Längen "L" durchlaufen:

import itertools

stuff = [1, 2, 3]
for L in range(0, len(stuff)+1):
    for subset in itertools.combinations(stuff, L):
        print(subset)

Oder - wenn Sie schick werden möchten (oder das Gehirn desjenigen biegen möchten, der Ihren Code nach Ihnen liest) - können Sie die Kette der "Kombinationen ()" - Generatoren generieren und diese durchlaufen:

from itertools import chain, combinations
def all_subsets(ss):
    return chain(*map(lambda x: combinations(ss, x), range(0, len(ss)+1)))

for subset in all_subsets(stuff):
    print(subset)

42
Danke für die Unterstützung! In den Wochen, seit ich die obige Antwort gepostet habe, habe ich festgestellt, dass der NAME des Konzepts für das, wonach Ben sucht, das "Powerset" des ursprünglichen Satzes von 15 Elementen ist. Eine Beispielimplementierung finden Sie auf der Standard-Python-Dokumentseite "itertools": docs.python.org/library/itertools.html (grep für "Powerset").
Dan H

37
Für alle, die bisher gelesen haben: Die powerset()Generatorfunktion im Abschnitt "Rezepte" der itertoolsDokumentation ist einfacher, benötigt möglicherweise weniger Speicher und ist wahrscheinlich schneller als die hier gezeigte Implementierung.
Martineau

Ist es möglich, alle Kombinationen in lexikografischer Reihenfolge zu generieren?
Guik

@guik: Ich bin zu 99% sicher, dass itertools.combinationsdie Artikelreihenfolge in den Listen erhalten bleibt. Wenn also die Eingabe lexikalisch sortiert ist, ist auch jede der Ausgaben.
Dan H

Ja, itertools.combinationserzeugt die Kombinationen von k unter n in lexikographischer Reihenfolge, aber nicht alle Kombinationen bis zu k unter n. powerseterzeugt alle Kombinationen bis k, aber meines Wissens nicht in lexikographischer Reihenfolge: Powerset ([1,2]) -> [(), (1,), (2,), (1, 2)] . Sollte es nicht sein: [(), (1,), (1, 2), (2,)]?
Guik

51

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ärzeichenfolgen der Länge N. Für jede Binärzeichenfolge 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:

  • Dies erfordert , dass Sie anrufen können len(...)auf items(Abhilfe: Wenn itemsso etwas wie ein iterable wie ein Generator ist, schalten Sie ihn in eine Liste zuerst mit items=list(_itemsArg))
  • Dies erfordert, dass die Reihenfolge der Iteration itemsnicht zufällig ist (Problemumgehung: Seien Sie nicht verrückt).
  • Dies erfordert , dass die Einzelteile sind einzigartig, oder sonst {2,2,1}und {2,1,1}wird sowohl Zusammenbruch {2,1}(Abhilfe: Verwendung collections.Counterals Drop-in - Ersatz für set, es ist im Grunde ein multiset ... wenn Sie zu den späteren Gebrauch benötigen , tuple(sorted(Counter(...).elements()))wenn Sie es brauchen , um hashable)

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

46

In Kommentaren unter der hoch bewerteten Antwort von @Dan H wird das powerset()Rezept in der itertoolsDokumentation erwähnt - einschließlich eines von Dan selbst . Doch bisher niemand hat es als Antwort gepostet. Da es wahrscheinlich eine der besseren, wenn nicht die beste Herangehensweise an das Problem ist - und von einem anderen Kommentator ein wenig ermutigt wird , wird es unten gezeigt. Die Funktion erzeugt alle eindeutigen Kombinationen der Listenelemente jeder möglichen Länge (einschließlich derjenigen, die Null und alle Elemente enthalten).

Hinweis : Wenn das subtil andere Ziel darin besteht, nur Kombinationen eindeutiger Elemente zu erhalten, ändern Sie die Zeile s = list(iterable)in s = list(set(iterable)), um doppelte Elemente zu entfernen. Unabhängig davon, dass die Tatsache, dass das iterableletztendlich zu einem listMittel wird, mit Generatoren funktioniert (im Gegensatz zu einigen anderen Antworten).

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)  # allows duplicate elements
    return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))

stuff = [1, 2, 3]
for i, combo in enumerate(powerset(stuff), 1):
    print('combo #{}: {}'.format(i, combo))

Ausgabe:

combo #1: ()
combo #2: (1,)
combo #3: (2,)
combo #4: (3,)
combo #5: (1, 2)
combo #6: (1, 3)
combo #7: (2, 3)
combo #8: (1, 2, 3)

Wofür ist die list()Konvertierung überhaupt?
AMC

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

35

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 zu drucken?
James Vickery

@JamesVickery Ja, Sie können entweder eine Liste außerhalb der Funktion erstellen und an diese anhängen oder (besser) die Funktion zu einem Generator machen. Schauen Sie sich das Schlüsselwort'ield
Dangercrow

new_data = copy.copy(data)- Diese Zeile ist
meines Erachtens

31

Dieser Einzeiler gibt Ihnen alle Kombinationen (zwischen 0und nElementen, wenn die ursprüngliche Liste / Menge nunterschiedliche Elemente enthält ) und verwendet die native Methode itertools.combinations:

Python 2

from itertools import combinations

input = ['a', 'b', 'c', 'd']

output = sum([map(list, combinations(input, i)) for i in range(len(input) + 1)], [])

Python 3

from itertools import combinations

input = ['a', 'b', 'c', 'd']

output = sum([list(map(list, combinations(input, i))) for i in range(len(input) + 1)], [])

Die Ausgabe wird sein:

[[],
 ['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']]

Probieren Sie es online aus:

http://ideone.com/COghfX


Dies ist eine Permutation
AdHominem

15
@AdHominem: Nein, das ist es nicht. Es ist eine Liste aller Kombinationen. Permutationen würden z ['b', 'a'].
naught101

TypeError: can only concatenate list (not "map") to list
0x48piraj

@ 0x48piraj: Danke, dass du es bemerkt hast, ich habe meine Antwort konsequent bearbeitet!
Mathieu Rodic

21

Ich stimme Dan H zu, dass Ben tatsächlich nach allen Kombinationen gefragt hat . itertools.combinations()gibt nicht alle Kombinationen an.

Ein weiteres Problem ist, wenn die iterierbare Eingabe groß ist, ist es vielleicht besser, einen Generator anstelle von allem in einer Liste zurückzugeben:

iterable = range(10)
for s in xrange(len(iterable)+1):
  for comb in itertools.combinations(iterable, s):
    yield comb

1
Schönes Beispiel. Ich liebe Generatoren ... und ich liebe Python, weil ich sie habe! In diesem Beispiel ist jeweils nur ein Kombinationsobjekt () vorhanden, und es wird jeweils eine der Kombinationen ausgegeben. (Vielleicht möchten Sie den def-Block dazu hinzufügen - als Verwendungsbeispiel.) Beachten Sie, dass meine Implementierung (mit chain (), wie oben angegeben) nicht allzu viel schlechter ist: Es ist wahr, dass alle len (iterierbaren) Generatoren bei erstellt werden einmal ... aber es werden NICHT alle 2 ** len (iterierbaren) Kombinationen gleichzeitig erstellt, da nach meinem Verständnis die Kette den ersten Generator "verbraucht", bevor aus den nachfolgenden gezogen wird.
Dan H

18

Dies ist ein Ansatz, der leicht auf alle Programmiersprachen übertragen werden kann, die die Rekursion unterstützen (keine itertools, keine Ausbeute, 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]]

14

Mit diesem einfachen Code können Sie alle Kombinationen einer Liste in Python generieren

import itertools

a = [1,2,3,4]
for i in xrange(0,len(a)+1):
   print list(itertools.combinations(a,i))

Ergebnis wäre:

[()]
[(1,), (2,), (3,), (4,)]
[(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]
[(1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4)]
[(1, 2, 3, 4)]

Fehler in diesem Code: Gibt den leeren Satz nicht zurück. Könnte xrange (0, ...) bedeuten, wurde aber nicht getestet. Bearbeiten : Ich habe Ihre Antwort bearbeitet, um sie zu beheben.
Ninjagecko

12

Ich dachte, ich würde diese Funktion für diejenigen hinzufügen, die eine Antwort suchen, ohne itertools oder andere zusätzliche Bibliotheken zu importieren.

def powerSet(items):
    """
    Power set generator: get all possible combinations of a list’s elements

    Input:
        items is a list
    Output:
        returns 2**n combination lists one at a time using a generator 

    Reference: edx.org 6.00.2x Lecture 2 - Decision Trees and dynamic programming
    """

    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

Verwendung des einfachen Ertragsgenerators:

for i in powerSet([1,2,3,4]):
    print (i, ", ",  end="")

Ausgabe aus dem obigen Verwendungsbeispiel:

[], [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],


Ich denke, das ist eine sehr nette Lösung.
Greentec

8

Hier ist noch eine andere Lösung (einzeilig), bei der die itertools.combinationsFunktion verwendet wird. Hier verwenden wir jedoch ein doppeltes Listenverständnis (im Gegensatz zu einer for-Schleife oder einer Summe):

def combs(x):
    return [c for i in range(len(x)+1) for c in combinations(x,i)]

Demo:

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

5
from itertools import permutations, combinations


features = ['A', 'B', 'C']
tmp = []
for i in range(len(features)):
    oc = combinations(features, i + 1)
    for c in oc:
        tmp.append(list(c))

Ausgabe

[
 ['A'],
 ['B'],
 ['C'],
 ['A', 'B'],
 ['A', 'C'],
 ['B', 'C'],
 ['A', 'B', 'C']
]

4

Unten finden Sie eine "rekursive Standardantwort", ähnlich der anderen ähnlichen Antwort https://stackoverflow.com/a/23743696/711085 . (Wir müssen uns realistisch nicht darum kümmern, dass der Stapelspeicherplatz knapp wird, da wir auf keinen Fall alle N! -Permutationen verarbeiten können.)

Es besucht nacheinander jedes Element und nimmt es entweder oder verlässt es (wir können die 2 ^ N-Kardinalität von diesem Algorithmus direkt sehen).

def combs(xs, i=0):
    if i==len(xs):
        yield ()
        return
    for c in combs(xs,i+1):
        yield c
        yield c+(xs[i],)

Demo:

>>> list( combs(range(5)) )
[(), (0,), (1,), (1, 0), (2,), (2, 0), (2, 1), (2, 1, 0), (3,), (3, 0), (3, 1), (3, 1, 0), (3, 2), (3, 2, 0), (3, 2, 1), (3, 2, 1, 0), (4,), (4, 0), (4, 1), (4, 1, 0), (4, 2), (4, 2, 0), (4, 2, 1), (4, 2, 1, 0), (4, 3), (4, 3, 0), (4, 3, 1), (4, 3, 1, 0), (4, 3, 2), (4, 3, 2, 0), (4, 3, 2, 1), (4, 3, 2, 1, 0)]

>>> list(sorted( combs(range(5)), key=len))
[(), 
 (0,), (1,), (2,), (3,), (4,), 
 (1, 0), (2, 0), (2, 1), (3, 0), (3, 1), (3, 2), (4, 0), (4, 1), (4, 2), (4, 3), 
 (2, 1, 0), (3, 1, 0), (3, 2, 0), (3, 2, 1), (4, 1, 0), (4, 2, 0), (4, 2, 1), (4, 3, 0), (4, 3, 1), (4, 3, 2), 
 (3, 2, 1, 0), (4, 2, 1, 0), (4, 3, 1, 0), (4, 3, 2, 0), (4, 3, 2, 1), 
 (4, 3, 2, 1, 0)]

>>> len(set(combs(range(5))))
32

2

Listenverständnis verwenden:

def selfCombine( list2Combine, length ):
    listCombined = str( ['list2Combine[i' + str( i ) + ']' for i in range( length )] ).replace( "'", '' ) \
                     + 'for i0 in range(len( list2Combine ) )'
    if length > 1:
        listCombined += str( [' for i' + str( i ) + ' in range( i' + str( i - 1 ) + ', len( list2Combine ) )' for i in range( 1, length )] )\
            .replace( "', '", ' ' )\
            .replace( "['", '' )\
            .replace( "']", '' )

    listCombined = '[' + listCombined + ']'
    listCombined = eval( listCombined )

    return listCombined

list2Combine = ['A', 'B', 'C']
listCombined = selfCombine( list2Combine, 2 )

Ausgabe wäre:

['A', 'A']
['A', 'B']
['A', 'C']
['B', 'B']
['B', 'C']
['C', 'C']

4
Dieser Vorschlag sieht vor, String-Mangeln durchzuführen, um Sets aufzubauen?!?! Heilige Krähe ... Und: es gibt nicht das Powerset zurück, sondern so etwas wie Kombinationen mit Ersetzung (). (Siehe docs.python.org/library/… )
Dan H

Dies entspricht in der Tat der Kombination von_mit_replacement () , aber zumindest auf meiner Box läuft dies etwas schneller als bei itertools . Was soll ich sagen, ich mag Listenverständnisse.
Zmk

1
Danke für die Antwort! Was ist mit create listCombined mit umgekehrten Listen wie ['A', 'A'], ['A', 'B'], ['A', 'C'], ['B', 'A'], [ 'B', 'B'], ['B', 'C'], ['C', 'A'], ['C', 'B'] und ['C', 'C'], einschließlich alles?
Karyo

Sehr interessant, aber meine Python ist nicht ganz in der Lage, die Feinheiten hier zu verstehen. Hat die Verwendung von listCombined in verschiedenen Bereichen etwas Besonderes und die Tatsache, dass die for-Schleife nur in einer Zeile steht? Ich versuche dies mit etwas Glück nach Java zu portieren.
Scott Biggs

2

Dieser Code verwendet einen einfachen Algorithmus mit verschachtelten Listen ...

# FUNCTION getCombos: To generate all combos of an input list, consider the following sets of nested lists...
#
#           [ [ [] ] ]
#           [ [ [] ], [ [A] ] ]
#           [ [ [] ], [ [A],[B] ],         [ [A,B] ] ]
#           [ [ [] ], [ [A],[B],[C] ],     [ [A,B],[A,C],[B,C] ],                   [ [A,B,C] ] ]
#           [ [ [] ], [ [A],[B],[C],[D] ], [ [A,B],[A,C],[B,C],[A,D],[B,D],[C,D] ], [ [A,B,C],[A,B,D],[A,C,D],[B,C,D] ], [ [A,B,C,D] ] ]
#
#  There is a set of lists for each number of items that will occur in a combo (including an empty set).
#  For each additional item, begin at the back of the list by adding an empty list, then taking the set of
#  lists in the previous column (e.g., in the last list, for sets of 3 items you take the existing set of
#  3-item lists and append to it additional lists created by appending the item (4) to the lists in the
#  next smallest item count set. In this case, for the three sets of 2-items in the previous list. Repeat
#  for each set of lists back to the initial list containing just the empty list.
#

def getCombos(listIn = ['A','B','C','D','E','F'] ):
    listCombos = [ [ [] ] ]     # list of lists of combos, seeded with a list containing only the empty list
    listSimple = []             # list to contain the final returned list of items (e.g., characters)

    for item in listIn:
        listCombos.append([])   # append an emtpy list to the end for each new item added
        for index in xrange(len(listCombos)-1, 0, -1):  # set the index range to work through the list
            for listPrev in listCombos[index-1]:        # retrieve the lists from the previous column
                listCur = listPrev[:]                   # create a new temporary list object to update
                listCur.append(item)                    # add the item to the previous list to make it current
                listCombos[index].append(listCur)       # list length and append it to the current list

                itemCombo = ''                          # Create a str to concatenate list items into a str
                for item in listCur:                    # concatenate the members of the lists to create
                    itemCombo += item                   # create a string of items
                listSimple.append(itemCombo)            # add to the final output list

    return [listSimple, listCombos]
# END getCombos()

Dieser Code scheint also [listOfCombinations, listOfCombinationsGroupedBySize] zurückzugeben. Wenn Sie mit dem Demo-Eingang arbeiten, erhalten Sie leider 63 statt 64 Elemente. Es scheint die leere Menge (in diesem Fall die leere Zeichenfolge "") zu fehlen .
Ninjagecko

2

Ich weiß, dass es weitaus praktischer ist, itertools zu verwenden, um alle Kombinationen zu erhalten, aber Sie können dies teilweise nur mit Listenverständnis erreichen, wenn Sie dies wünschen, vorausgesetzt, Sie möchten viel codieren

Für Kombinationen von zwei Paaren:

    lambda l: [(a, b) for i, a in enumerate(l) for b in l[i+1:]]


Und für Kombinationen von drei Paaren ist es so einfach:

    lambda l: [(a, b, c) for i, a in enumerate(l) for ii, b in enumerate(l[i+1:]) for c in l[i+ii+2:]]


Das Ergebnis ist identisch mit der Verwendung von itertools.combinations:

import itertools
combs_3 = lambda l: [
    (a, b, c) for i, a in enumerate(l) 
    for ii, b in enumerate(l[i+1:]) 
    for c in l[i+ii+2:]
]
data = ((1, 2), 5, "a", None)
print("A:", list(itertools.combinations(data, 3)))
print("B:", combs_3(data))
# A: [((1, 2), 5, 'a'), ((1, 2), 5, None), ((1, 2), 'a', None), (5, 'a', None)]
# B: [((1, 2), 5, 'a'), ((1, 2), 5, None), ((1, 2), 'a', None), (5, 'a', None)]

2

Ohne itertools zu verwenden:

def combine(inp):
    return combine_helper(inp, [], [])


def combine_helper(inp, temp, ans):
    for i in range(len(inp)):
        current = inp[i]
        remaining = inp[i + 1:]
        temp.append(current)
        ans.append(tuple(temp))
        combine_helper(remaining, temp, ans)
        temp.pop()
    return ans


print(combine(['a', 'b', 'c', 'd']))

2

Hier sind zwei Implementierungen von itertools.combinations

Eine, die eine Liste zurückgibt

def combinations(lst, depth, start=0, items=[]):
    if depth <= 0:
        return [items]
    out = []
    for i in range(start, len(lst)):
        out += combinations(lst, depth - 1, i + 1, items + [lst[i]])
    return out

Man gibt einen Generator zurück

def combinations(lst, depth, start=0, prepend=[]):
    if depth <= 0:
        yield prepend
    else:
        for i in range(start, len(lst)):
            for c in combinations(lst, depth - 1, i + 1, prepend + [lst[i]]):
                yield c

Bitte beachten Sie, dass die Bereitstellung einer Hilfsfunktion für diese empfohlen wird, da das Argument prepend statisch ist und sich nicht bei jedem Aufruf ändert

print([c for c in combinations([1, 2, 3, 4], 3)])
# [[1, 2, 3], [1, 2, 4], [1, 3, 4], [2, 3, 4]]

# get a hold of prepend
prepend = [c for c in combinations([], -1)][0]
prepend.append(None)

print([c for c in combinations([1, 2, 3, 4], 3)])
# [[None, 1, 2, 3], [None, 1, 2, 4], [None, 1, 3, 4], [None, 2, 3, 4]]

Dies ist ein sehr oberflächlicher Fall, aber besser auf Nummer sicher gehen


2

Wie wäre es damit .. verwendet eine Zeichenfolge anstelle von Liste, aber das gleiche .. Zeichenfolge kann wie eine Liste in Python behandelt werden:

def comb(s, res):
    if not s: return
    res.add(s)
    for i in range(0, len(s)):
        t = s[0:i] + s[i + 1:]
        comb(t, res)

res = set()
comb('game', res) 

print(res)

2

Kombination aus itertools

import itertools
col_names = ["aa","bb", "cc", "dd"]
all_combinations = itertools.chain(*[itertools.combinations(col_names,i+1) for i,_ in enumerate(col_names)])
print(list(all_combinations))

Vielen Dank


2

Ohne itertools in Python 3 könnten Sie so etwas tun:

def combinations(arr, carry):
    for i in range(len(arr)):
        yield carry + arr[i]
        yield from combinations(arr[i + 1:], carry + arr[i])

wo anfangs carry = "".


2

3 Funktionen:

  1. Alle Kombinationen von n Elementen Liste
  2. Alle Kombinationen von n Elementen werden aufgelistet, wenn die Reihenfolge nicht eindeutig ist
  3. alle Permutationen
import sys

def permutations(a):
    return combinations(a, len(a))

def combinations(a, n):
    if n == 1:
        for x in a:
            yield [x]
    else:
        for i in range(len(a)):
            for x in combinations(a[:i] + a[i+1:], n-1):
                yield [a[i]] + x

def combinationsNoOrder(a, n):
    if n == 1:
        for x in a:
            yield [x]
    else:
        for i in range(len(a)):
            for x in combinationsNoOrder(a[:i], n-1):
                yield [a[i]] + x

if __name__ == "__main__":
    for s in combinations(list(map(int, sys.argv[2:])), int(sys.argv[1])):
        print(s)

Ich mag das sehr gerne!!! Vielen Dank!!! Die kombinatorischen Funktionen von Python sind allerdings etwas seltsam. In der Mathematik wäre die Funktion "Kombinationen" Variationen, und "KombinationenNoOrder" sind tatsächlich Kombinationen. Ich würde vermuten, dass dies Leute verwirrt, die aus dem Bereich der Mathematik zu Python kommen, wie diesmal bei mir. Wie auch immer, eine schöne Lösung, vielen Dank!
Đumić Branislav

1

Dies ist meine Implementierung

    def get_combinations(list_of_things):
    """gets every combination of things in a list returned as a list of lists

    Should be read : add all combinations of a certain size to the end of a list for every possible size in the
    the list_of_things.

    """
    list_of_combinations = [list(combinations_of_a_certain_size)
                            for possible_size_of_combinations in range(1,  len(list_of_things))
                            for combinations_of_a_certain_size in itertools.combinations(list_of_things,
                                                                                         possible_size_of_combinations)]
    return list_of_combinations

1
Was löst Ihre Implementierung besser als die vorherigen Implementierungen, die hier veröffentlicht wurden?
user1767754

0

Sie können auch die Powerset- Funktion aus dem hervorragenden more_itertoolsPaket verwenden.

from more_itertools import powerset

l = [1,2,3]
list(powerset(l))

# [(), (1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]

Wir können auch überprüfen, ob es die Anforderungen von OP erfüllt

from more_itertools import ilen

assert ilen(powerset(range(15))) == 32_768

-1
def combinations(iterable, r):
# combinations('ABCD', 2) --> AB AC AD BC BD CD
# combinations(range(4), 3) --> 012 013 023 123
pool = tuple(iterable)
n = len(pool)
if r > n:
    return
indices = range(r)
yield tuple(pool[i] for i in indices)
while True:
    for i in reversed(range(r)):
        if indices[i] != i + n - r:
            break
    else:
        return
    indices[i] += 1
    for j in range(i+1, r):
        indices[j] = indices[j-1] + 1
    yield tuple(pool[i] for i in indices)


x = [2, 3, 4, 5, 1, 6, 4, 7, 8, 3, 9]
for i in combinations(x, 2):
    print i

1
Wenn ich recht habe, ist dies der genaue Code, der aus der Python-Dokumentation [ docs.python.org/3.6/library/itertools.html ] kopiert wurde . Wenn ja, geben Sie bitte die Quelle an.
GabrielChu

interessanter Ansatz
pelos

-1

Wenn jemand nach einer umgekehrten Liste sucht, wie ich es war:

stuff = [1, 2, 3, 4]

def reverse(bla, y):
    for subset in itertools.combinations(bla, len(bla)-y):
        print list(subset)
    if y != len(bla):
        y += 1
        reverse(bla, y)

reverse(stuff, 1)

-1
flag = 0
requiredCals =12
from itertools import chain, combinations

def powerset(iterable):
    s = list(iterable)  # allows duplicate elements
    return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))

stuff = [2,9,5,1,6]
for i, combo in enumerate(powerset(stuff), 1):
    if(len(combo)>0):
        #print(combo , sum(combo))
        if(sum(combo)== requiredCals):
            flag = 1
            break
if(flag==1):
    print('True')
else:
    print('else')
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.