it-swarm.com.de

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

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

Ich habe etwas Code (von Googling) gefunden, das 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, wäre, 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? Vielleicht mit map()?

345
Ben

Schauen Sie sich itertools.combinations an:

itertools.combinations(iterable, r)

Gibt r-Längen-Untersequenzen von Elementen aus der Eingabe iterabel zurück.

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

Seit 2.6 sind Batterien enthalten!

381
James Brady

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 schlau werden möchten (oder das Gehirn desjenigen, der Ihren Code nach Ihnen liest, biegen möchten) - können Sie die Kette von "Combinations ()" - 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)
567
Dan H

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 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 setzt voraus, dass Sie len(...) für items aufrufen können (Workaround: Wenn items so etwas wie ein Iterable wie ein Generator ist, machen Sie es zuerst mit items=list(_itemsArg) zu einer Liste)
  • Dies setzt voraus, dass die Reihenfolge der Iteration in items nicht zufällig ist (Problemumgehung: seien Sie nicht verrückt)
  • Dies setzt voraus, dass die Elemente eindeutig sind. Andernfalls werden {2,2,1} und {2,1,1} zu {2,1} reduziert (Problemumgehung: Verwenden Sie collections.Counter als Ersatz für set; es ist im Grunde ein Multiset ... obwohl Sie möglicherweise später Tuple(sorted(Counter(...).elements())) verwenden müssen, wenn Sie es brauchen, um hashbar zu sein)

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

In Kommentaren unter dem hoch gelobten answer von @Dan H wird das powerset() -Rezept in der itertools -Dokumentation erwähnt - einschließlich eines von - Dan selbst . Allerdings hat es bisher noch niemand als Antwort gepostet. Da es wahrscheinlich eine der besten, wenn nicht die beste Herangehensweise an das Problem ist - und eine kleine Ermutigung von einem anderen Kommentator erhalten hat, wird es unten gezeigt. Die Funktion erzeugt alle eindeutigen Kombinationen der Listenelemente von jeder möglichen Länge (einschließlich solcher, 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. Ungeachtet dessen bedeutet die Tatsache, dass das iterable letztendlich in ein list verwandelt wird, dass es mit Generatoren funktioniert (im Gegensatz zu mehreren der 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)
40
martineau

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']
31
darxtrix

Dieser Einzeiler gibt Ihnen alle Kombinationen (zwischen 0 und n Elementen, wenn die ursprüngliche Liste/Menge n verschiedene 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

28
Mathieu Rodic

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 Eingabe-Iterationsrate groß ist, es vielleicht besser ist, 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
21
HongboZhu

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)]
14

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

Einfache Verwendung des Ertragsgenerators:

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

Ausgabe des obigen Verwendungsbeispiels:

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

8
user3078690

Dies ist ein Ansatz, der leicht auf alle Programmiersprachen übertragen werden kann, die die Rekursion unterstützen (keine Itertools, kein Ertrag, 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]]
8
Jonathan R

Hier ist noch eine andere Lösung (einzeilig), bei der die Funktion itertools.combinations verwendet wird. Hier verwenden wir jedoch ein doppeltes Listenverständnis (im Gegensatz zu einer for-Schleife oder einer for-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)]
7
ninjagecko

Dies könnte mit itertools geschehen

Für Permutationen

Diese Methode nimmt eine Liste als Eingabe und gibt eine Objektliste von Tupeln zurück, die eine Permutation der Länge L in einer Listenform enthalten.

# A Python program to print all  
# permutations of given length 
from itertools import permutations 

# Get all permutations of length 2 
# and length 2 
perm = permutations([1, 2, 3], 2) 

# Print the obtained permutations 
for i in list(perm): 
    print (i) 

Zur Kombination

Diese Methode nimmt eine Liste und eine Eingabe r als Eingabe und gibt eine Objektliste von Tupeln zurück, die alle möglichen Kombinationen der Länge r in einer Listenform enthalten.

# A Python program to print all  
# combinations of given length 
from itertools import combinations 

# Get all combinations of [1, 2, 3] 
# and length 2 
comb = combinations([1, 2, 3], 2) 

# Print the obtained combinations 
for i in list(comb): 
    print (i) 

siehe dies

5
Umer

Nachfolgend finden Sie eine "standardmäßige rekursive Antwort", ähnlich der anderen ähnlichen Antwort https://stackoverflow.com/a/23743696/711085 . (Wir müssen uns nicht realistisch darum sorgen, dass nicht mehr genügend Speicherplatz zur Verfügung steht, da wir auf keinen Fall alle N! -Permutationen verarbeiten können.)

Es besucht nacheinander jedes Element und nimmt es entweder auf 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
4
ninjagecko

Ohneitertools 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 = "".

Ohne Verwendung von itertools:

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

Wie wäre es damit ... wenn Sie einen String anstelle von list verwenden, aber das Gleiche ... string kann in Python wie eine Liste 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
Apurva Singh

Verwenden des Listenverständnisses:

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 )

Die Ausgabe wäre:

['A', 'A']
['A', 'B']
['A', 'C']
['B', 'B']
['B', 'C']
['C', 'C']
2
zmk

Ich weiß, es ist weitaus praktischer, itertools zu verwenden, um die alle Kombinationen zu erhalten, aber Sie können erreichen Sie dies teilweise nur mit Listenverständnis, wenn Sie dies zufällig 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:]]

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
Cynadyde

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
Abhishek

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()
2
TiPS

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 das Bereitstellen einer Hilfsfunktion für diese empfohlen wird, da das Voranstellungsargument 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
Modar

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
Andres Ulloa
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
0
Anoop

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)
0
Expat C