Come ottenere tutte le possibili combinazioni degli elementi di un elenco?


423

Ho un elenco con 15 numeri e ho bisogno di scrivere del codice che produca tutte le 32.768 combinazioni di quei numeri.

Ho trovato del codice (di Google) che apparentemente fa quello che sto cercando, ma ho trovato il codice abbastanza opaco e diffido nell'usarlo. Inoltre ho la sensazione che ci debba essere una soluzione più elegante.

L'unica cosa che mi viene in mente sarebbe semplicemente scorrere gli interi decimali 1–32768 e convertirli in binari e usare la rappresentazione binaria come filtro per selezionare i numeri appropriati.

Qualcuno sa di un modo migliore? Usando map(), forse?


9
I lettori devono tenere presente che se gli elementi dell'elenco sono univoci è una considerazione estremamente importante, poiché molti algoritmi supereranno quindi alcuni sottoinsiemi (ad esempio 'abccc' -> ['', 'a', 'b', 'c', 'c' , 'c', 'ac', 'ac', 'ac', ...]. Una soluzione semplice è semplicemente spingere tutti gli elementi in un set prima di ottenere le loro permutazioni.
ninjagecko,

@ninjagecko L'uso della libreria Set non è efficiente in quanto ognuno è O (n) al meglio. Quindi l'aggiunta di n funzioni a un set è in realtà O (n ^ 2)!
Scott Biggs,

Dalla lettura attenta della domanda, sembra che l'OP stia chiedendo il PowerSet del suo elenco di 15 numeri, non tutte le combinazioni. Penso che questo possa essere il motivo per cui le risposte sono ovunque.
Scott Biggs,

@Scott Biggs: sei sicuro di prendere Python qui? Gli inserimenti e le ricerche impostati sono O (1) caso medio. Sono come dizionari. Usano l'hashing. Python non ha una libreria di set speciali (è nella libreria standard). Stiamo inserendo numeri non funzioni. (Sarebbe ancora inefficiente utilizzare la memoria O (2 ^ n); la soluzione adeguata per le persone che desiderano combinazioni piuttosto che il powerset è una semplice implementazione ricorsiva, o product, ecc.)
ninjagecko,

Risposte:


467

Dai un'occhiata a itertools.combinations :

itertools.combinations(iterable, r)

Restituisce le sottosequenze di lunghezza r degli elementi dall'ingresso iterabile.

Le combinazioni sono emesse in ordine lessicografico. Pertanto, se l'input iterabile viene ordinato, le tuple combinate verranno prodotte in ordine.

Dal 2.6, le batterie sono incluse!


31
puoi semplicemente elencarlo tutto. list(itertools.combinations(iterable, r))
silgon,

1
c'è qualcosa che non richiede r, cioè combinazioni di sottosequenze di lunghezza degli elementi.
mLstudent33

630

Questa risposta ha mancato un aspetto: l'OP ha chiesto TUTTE le combinazioni ... non solo le combinazioni di lunghezza "r".

Quindi dovresti o passare in rassegna tutte le lunghezze "L":

import itertools

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

Oppure - se vuoi diventare elegante (o piegare il cervello di chiunque legga il tuo codice dopo di te) - puoi generare la catena di generatori di "combinazioni ()" e scorrere attraverso:

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
Grazie per il supporto! Nelle settimane da quando ho pubblicato la risposta di cui sopra, ho scoperto che il NOME del concetto per ciò che Ben sta cercando è il "powerset" del set originale di 15 elementi. In effetti, viene fornita un'implementazione di esempio nella pagina doc "itertools" di Python standard: docs.python.org/library/itertools.html (grep per "powerset").
Dan H,

38
Per chiunque legga fino a questo punto: la powerset()funzione generatore nella sezione ricette della itertoolsdocumentazione è più semplice, utilizza potenzialmente meno memoria ed è probabilmente più veloce dell'implementazione mostrata qui.
martineau,

È possibile generare tutte le combinazioni in ordine lessicografico?
Guik,

@guik: Sono sicuro al 99% che itertools.combinationsconserva l'ordine degli articoli nelle liste che produce. Pertanto, se l'ingresso è ordinato in modo lessicale, lo sarà anche ciascuno degli output.
Dan H

Sì, itertools.combinationsgenera le combinazioni di k tra n in ordine lessicografico, ma non tutte le combinazioni fino a k tra n. powersetgenera tutte le combinazioni fino a k, ma non in ordine lessicografico per quanto ne capisco: powerset ([1,2]) -> [(), (1,), (2,), (1, 2)] . Non dovrebbe essere: [(), (1,), (1, 2), (2,)]?
Guik,

52

Ecco un lazy one-liner, anche usando itertools:

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

Idea principale dietro questa risposta: ci sono 2 ^ N combinazioni - uguale al numero di stringhe binarie di lunghezza N. Per ogni stringa binaria, scegli tutti gli elementi corrispondenti a un "1".

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

Cose da considerare:

  • Ciò richiede che si può chiamare len(...)il items(soluzione: se itemsè qualcosa di simile a un iterabile come un generatore, trasformarlo in un elenco prima con items=list(_itemsArg))
  • Ciò richiede che l'ordine di iterazione itemsnon sia casuale (soluzione alternativa: non essere pazzo)
  • Ciò richiede che gli elementi sono unici, altrimenti {2,2,1}e {2,1,1}saranno entrambi collasso {2,1}(soluzione: l'uso collections.Countercome un rimpiazzo per set: è fondamentalmente un multinsieme ... anche se potrebbe essere necessario un uso successivo tuple(sorted(Counter(...).elements()))se ne avete bisogno di essere hashable)

dimostrazione

>>> 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

Nei commenti sotto la risposta altamente votata di @Dan H, si fa menzione della powerset()ricetta nella itertoolsdocumentazione, inclusa quella dello stesso Dan . Tuttavia , finora nessuno lo ha pubblicato come risposta. Dal momento che è probabilmente uno dei migliori se non il migliore approccio al problema e dato un piccolo incoraggiamento da un altro commentatore, è mostrato di seguito. La funzione produce tutte le combinazioni uniche degli elementi dell'elenco di ogni lunghezza possibile (compresi quelli che contengono zero e tutti gli elementi).

Nota : se l'obiettivo, leggermente diverso, è ottenere solo combinazioni di elementi unici, modificare la linea s = list(iterable)in s = list(set(iterable))per eliminare eventuali elementi duplicati. Indipendentemente da ciò, il fatto che alla iterablefine si trasformi in un listmezzo funzionerà con i generatori (a differenza di molte altre risposte).

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

Produzione:

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)

A cosa serve la list()conversione?
AMC,

@Alexander: per consentire la determinazione della lunghezza dell'iterabile.
martineau,

36

Eccone uno che usa la ricorsione:

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

Questo può essere modificato per restituire un elenco di elenchi invece di stampare?
James Vickery,

@JamesVickery sì, potresti guardare a fare un elenco al di fuori della funzione e ad aggiungere a quello, o (meglio) rendere la funzione un generatore, dare un'occhiata alla parola chiave 'yield' :)
Dangercrow

new_data = copy.copy(data)- questa riga è ridondante per quanto vedo, non influenza nulla
Dmitriy Fialkovskiy

31

Questo one-liner offre tutte le combinazioni (tra 0e gli nelementi se l'elenco / set originale contiene nelementi distinti) e utilizza il metodo nativo 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)], [])

L'output sarà:

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

Provalo online:

http://ideone.com/COghfX


Questa è una permutazione
AdHominem,

15
@AdHominem: no, non lo è. È un elenco di tutte le combinazioni. Le permutazioni includono, ad es ['b', 'a'].
naught101

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

@ 0x48piraj: grazie per aver notato, ho modificato la mia risposta di conseguenza!
Mathieu Rodic,

21

Concordo con Dan H sul fatto che Ben abbia effettivamente chiesto tutte le combinazioni. itertools.combinations()non dà tutte le combinazioni.

Un altro problema è che, se l'input iterabile è grande, è forse meglio restituire un generatore invece di tutto in un elenco:

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

1
Bell'esempio Adoro i generatori ... e adoro Python per averli! Questo esempio ha un solo oggetto combinazioni () alla volta e produce una delle combinazioni alla volta. (Forse vuoi aggiungere il blocco def attorno a questo - come esempio di utilizzo.) Nota che la mia implementazione (con chain (), data sopra) non è molto peggio: è vero che crea tutti i generatori len (iterabili) a una volta ... ma NON crea contemporaneamente tutte le 2 ** len (iterabili) combinazioni, poiché - per quanto ne so - la catena "utilizza" il primo generatore prima di attingere da quelle successive.
Dan H,

18

Questo è un approccio che può essere facilmente trasferito in tutti i linguaggi di programmazione che supportano la ricorsione (nessun itertools, nessuna resa, nessuna comprensione dell'elenco) :

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

Ah! Bella implementazione Riconosco HEAD = a [0], TAIL = a [1:] da Prolog. Oppure car = a [0], cdr = a [1:] da Lisp. Mi chiedo se potremmo usare la memoizzazione qui ...
Javier Ruiz

Vero. L'elenco delle sezioni è O (k) dove k è la lunghezza della sezione. Immagino che si potrebbe accelerare questo facendo una ricerca in una mappa che lo renderebbe O (1) in tutte le corse, tranne la prima. Si noti tuttavia che questa implementazione non deve essere referenziata per le prestazioni. Per questo esistono implementazioni migliori. Questa implementazione è solo per semplicità e portabilità nella maggior parte delle altre lingue.
Jonathan R

14

Puoi generare tutte le combinazioni di un elenco in Python usando questo semplice codice

import itertools

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

Il risultato sarebbe:

[()]
[(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)]

Bug in questo codice: non restituisce il set vuoto. Potrebbe significare xrange (0, ...) ma non è stato testato. modifica : sono andato avanti e ho modificato la tua risposta per risolverlo.
ninjagecko,

13

Ho pensato di aggiungere questa funzione a chi cerca una risposta senza importare itertools o altre librerie extra.

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

Utilizzo semplice del generatore di rendimento:

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

Output dall'esempio di utilizzo sopra:

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


Penso che questa sia una soluzione molto accurata.
greentec,

8

Ecco ancora un'altra soluzione (one-liner), che prevede l'uso della itertools.combinationsfunzione, ma qui usiamo una doppia comprensione del listino (al contrario di un ciclo for o sum):

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

produzione

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

4

Di seguito è una "risposta ricorsiva standard", simile all'altra risposta simile https://stackoverflow.com/a/23743696/711085 . (Non dobbiamo realisticamente preoccuparci di rimanere senza spazio di stack poiché non è possibile elaborare tutte le permutazioni di N!).

Visita ogni elemento a sua volta e lo prende o lo lascia (possiamo vedere direttamente la cardinalità 2 ^ N da questo algoritmo).

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

Utilizzando la comprensione dell'elenco:

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 )

L'output sarebbe:

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

4
Questa proposta è di manipolare le stringhe per costruire set?!?! Santo corvo .... E: non sta restituendo il powerset, ma piuttosto qualcosa come combinazioni_with_replacement (). (Vedi docs.python.org/library/… )
Dan H,

Questo in effetti fa lo stesso di combinazione_con_replacement () , ma almeno sulla mia scatola funziona leggermente più velocemente degli itertools . Cosa posso dire, mi piace la comprensione delle liste.
zmk

1
Grazie per la risposta! Che ne dici di creare un elenco Combinato con elenchi invertiti come ['A', 'A'], ['A', 'B'], ['A', 'C'], ['B', 'A'], [ 'B', 'B'], ['B', 'C'], ['C', 'A'], ['C', 'B'] e ['C', 'C'] che includono qualunque cosa?
Karyo,

Molto interessante, ma il mio pitone non è abbastanza in grado di comprendere le sottigliezze qui. C'è qualcosa di speciale nell'uso di listCombined in diversi ambiti e nel fatto che il ciclo for è tutto in una riga? Sto provando a portarlo su Java con poca fortuna.
Scott Biggs,

2

Questo codice utilizza un semplice algoritmo con elenchi nidificati ...

# 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()

Quindi ciò che questo codice sembra fare è return [listOfCombinations, listOfCombinationsGroupedBySize]. Sfortunatamente quando eseguito con l'input demo fornisce 63 elementi anziché 64; sembra che manchi l'insieme vuoto (in questo caso, la stringa vuota "").
ninjagecko,

2

So che è molto più pratico usare itertools per ottenere tutte le combinazioni, ma puoi ottenerlo in parte solo con la comprensione dell'elenco se ti capita di desiderare, a condizione che tu voglia programmare molto

Per combinazioni di due coppie:

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


E, per combinazioni di tre coppie, è facile come questo:

    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:]]


Il risultato è identico all'utilizzo di 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

Senza usare 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

Ecco due implementazioni di itertools.combinations

Uno che restituisce un elenco

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

Uno restituisce un generatore

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

Si noti che fornire una funzione di supporto a questi è consigliato perché l'argomento prepend è statico e non cambia con ogni chiamata

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

Questo è un caso molto superficiale, ma è meglio prevenire che curare


2

Che ne dici di questo ... ho usato una stringa invece della lista, ma la stessa cosa .. la stringa può essere trattata come una lista in Python:

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

Combinazione di 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))

Grazie


2

Senza itertools in Python 3 potresti fare qualcosa del genere:

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

dove inizialmente carry = "".


2

3 funzioni:

  1. tutte le combinazioni della lista n elementi
  2. tutte le combinazioni di n elementi elencano dove l'ordine non è distinto
  3. tutte le permutazioni
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)

Questo mi piace molto!!! Grazie!!! Le funzioni combinatorie di Python sono un po 'strane però. In matematica la funzione "combinazioni" sarebbe Variazioni, e "combinazioniNoOrder" sono in realtà combinazioni. Immagino che ciò confonda le persone che arrivano al pitone dal ramo della matematica, come ha fatto per me questa volta. Comunque, una bella soluzione, grazie mille per il guadagno!
Đumić Branislav il

1

Questa è la mia implementazione

    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
Qual è la tua implementazione che risolve meglio delle precedenti implementazioni pubblicate qui.
user1767754

0

Puoi anche usare la funzione powerset dal more_itertoolspacchetto eccellente .

from more_itertools import powerset

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

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

Possiamo anche verificare che soddisfi i requisiti di OP

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
Se ho ragione, questo è il codice esatto copiato dalla documentazione di Python [ docs.python.org/3.6/library/itertools.html ]. In tal caso, si prega di fare riferimento alla fonte.
GabrielChu,

approccio interessante
pelos,

-1

Se qualcuno è alla ricerca di un elenco invertito, come se fossi:

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')
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.