¿Cómo obtener todas las combinaciones posibles de los elementos de una lista?

423

Tengo una lista con 15 números y necesito escribir un código que produzca las 32,768 combinaciones de esos números.

Encontré un código (buscando en Google) que aparentemente hace lo que estoy buscando, pero encontré el código bastante opaco y desconfío de usarlo. Además, tengo la sensación de que debe haber una solución más elegante.

Lo único que se me ocurre sería recorrer los enteros decimales 1–32768 y convertirlos en binarios, y usar la representación binaria como filtro para seleccionar los números apropiados.

¿Alguien sabe de una mejor manera? ¿Usando map(), tal vez?

Ben
fuente
99
Los lectores deben tener en cuenta que si los elementos de la lista son únicos es una consideración extremadamente importante, ya que muchos algoritmos sobrecontarán algún subconjunto (por ejemplo, 'abccc' -> ['', 'a', 'b', 'c', 'c' , 'c', 'ac', 'ac', 'ac', ...]. Una solución fácil es simplemente empujar todos los elementos en un conjunto antes de obtener sus permutaciones.
ninjagecko
@ninjagecko Usar la biblioteca Set no es eficiente ya que cada uno es O (n) en el mejor de los casos. ¡Por lo tanto, agregar n funciones a un conjunto es en realidad O (n ^ 2)!
Scott Biggs
Al leer cuidadosamente la pregunta, parece que el OP está pidiendo el PowerSet de su lista de 15 números, no todas las combinaciones. Creo que esta puede ser la razón por la cual las respuestas están por todas partes.
Scott Biggs
@Scott Biggs: ¿estás seguro de que estás tomando Python aquí? Las inserciones y búsquedas de conjunto son O (1) caso promedio. Son como los diccionarios. Usan hashing. Python no tiene una biblioteca de conjunto especial (está en la biblioteca estándar). Estamos insertando números aquí, no funciones. (Todavía sería ineficiente usar la memoria O (2 ^ n); la solución adecuada para las personas que desean combinaciones en lugar del conjunto de potencia es una implementación recursiva simple product, etc.)
ninjagecko

Respuestas:

467

Echa un vistazo a itertools.combinations :

itertools.combinations(iterable, r)

Devuelve subsecuencias de longitud r de elementos de la entrada iterable.

Las combinaciones se emiten en orden de clasificación lexicográfica. Entonces, si la entrada iterable está ordenada, las tuplas combinadas se producirán en orden ordenado.

¡Desde 2.6, las baterías están incluidas!

James Brady
fuente
31
puedes enumerarlo todo. list(itertools.combinations(iterable, r))
silgon
1
¿Hay algo que no requiera r, es decir, combinaciones de subsecuencias de elementos de cualquier longitud?
mLstudent33
630

Esta respuesta perdió un aspecto: el OP solicitó TODAS las combinaciones ... no solo combinaciones de longitud "r".

Así que tendrías que recorrer todas las longitudes "L":

import itertools

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

O bien, si desea ponerse elegante (o doblar el cerebro de quien lea su código después de usted), puede generar la cadena de generadores de "combinaciones ()" e iterar a través de eso:

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)
Dan H
fuente
42
¡Gracias por el apoyo! En las semanas desde que publiqué la respuesta anterior, descubrí que el NOMBRE del concepto de lo que Ben está buscando es el "conjunto de poder" del conjunto original de 15 elementos. De hecho, se proporciona un ejemplo de implementación en la página de documentos estándar de "itertools" de python: docs.python.org/library/itertools.html (grep para "powerset").
Dan H
38
Para cualquiera que lea hasta aquí: la powerset()función de generador en la sección de recetas de la itertoolsdocumentación es más simple, potencialmente usa menos memoria y es probable que sea más rápida que la implementación que se muestra aquí.
Martineau
¿Es posible generar todas las combinaciones en orden lexicográfico?
guik
@ guik: estoy 99% seguro de que itertools.combinationsconserva el orden del artículo en las listas que produce. Por lo tanto, si la entrada está ordenada léxicamente, entonces cada una de las salidas también lo estará.
Dan H
Sí, itertools.combinationsgenera las combinaciones de k entre n en orden lexicográfico, pero no todas las combinaciones hasta k entre n. powersetgenera todas las combinaciones hasta k, pero no en orden lexicográfico por lo que yo entiendo: powerset ([1,2]) -> [(), (1,), (2,), (1, 2)] . ¿No debería ser: [(), (1,), (1, 2), (2,)]?
guik
52

Aquí hay una línea perezosa, que también usa 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 principal detrás de esta respuesta: hay 2 ^ N combinaciones, lo mismo que el número de cadenas binarias de longitud N. Para cada cadena binaria, elige todos los elementos correspondientes a un "1".

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

Cosas para considerar:

  • Esto requiere que se le puede llamar len(...)en items(solución: si itemses algo así como un iterable como un generador, lo convierten en una lista primero con items=list(_itemsArg))
  • Esto requiere que el orden de iteración itemsno sea aleatorio (solución alternativa: no se vuelva loco)
  • Esto requiere que los artículos son únicos, o de lo contrario {2,2,1}y {2,1,1}se colapso tanto a {2,1}(solución: el uso collections.Countercomo una gota en el reemplazo para set, es básicamente un conjunto múltiple ... aunque puede que necesite su uso posterior tuple(sorted(Counter(...).elements())), si lo necesita para ser hashable)

Manifestación

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

En los comentarios bajo la respuesta altamente votada por @Dan H, se menciona la powerset()receta en la itertoolsdocumentación, incluida una del propio Dan . Sin embargo , hasta ahora nadie lo ha publicado como respuesta. Dado que es probablemente uno de los mejores, si no el mejor, del problema, y ​​dado un poco de aliento de otro comentarista, se muestra a continuación. La función produce todas las combinaciones únicas de los elementos de la lista de todas las longitudes posibles (incluidas las que contienen cero y todos los elementos).

Nota : Si el, sutilmente diferente, meta es obtener sólo las combinaciones de elementos únicos, cambie la línea s = list(iterable)de s = list(set(iterable))eliminar todo elemento duplicadas. En cualquier caso, el hecho de que iterablefinalmente se convierta en un listmedio funcionará con generadores (a diferencia de varias de las otras respuestas).

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

Salida:

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)
Martineau
fuente
¿Para qué es la list()conversión en primer lugar?
AMC
@Alexander: para permitir que se determine la longitud del iterable.
Martineau
36

Aquí hay uno que usa recursión:

>>> 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']
darxtrix
fuente
¿Se puede modificar para devolver una lista de listas en lugar de imprimir?
James Vickery
@JamesVickery sí, podrías mirar hacer una lista fuera de la función y agregarla, o (mejor) hacer que la función sea un generador, mira la palabra clave 'rendimiento' :)
Dangercrow
new_data = copy.copy(data)- Esta fila es redundante por lo que veo, no influye en nada
Dmitriy Fialkovskiy
31

Esta línea le brinda todas las combinaciones (entre 0y nelementos si la lista / conjunto original contiene nelementos distintos) y utiliza el método 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)], [])

El resultado será:

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

Pruébalo en línea:

http://ideone.com/COghfX

Mathieu Rodic
fuente
Esta es una permutación
argumento ad hominem
15
@AdHominem: no, no lo es. Es una lista de todas las combinaciones. Las permutaciones incluirían, por ejemplo ['b', 'a'].
naught101
TypeError: can only concatenate list (not "map") to list
0x48piraj
@ 0x48piraj: gracias por notarlo, ¡edité mi respuesta en consecuencia!
Mathieu Rodic
21

Estoy de acuerdo con Dan H en que Ben realmente pidió todas las combinaciones. itertools.combinations()No da todas las combinaciones.

Otro problema es que, si la entrada iterable es grande, quizás sea mejor devolver un generador en lugar de todo en una lista:

iterable = range(10)
for s in xrange(len(iterable)+1):
  for comb in itertools.combinations(iterable, s):
    yield comb
HongboZhu
fuente
1
Buen ejemplo ¡Amo los generadores ... y amo a Python por tenerlos! Este ejemplo solo tiene un objeto de combinaciones () alrededor a la vez, y produce una de las combinaciones a la vez. (Quizás desee agregar el bloque def alrededor de esto, como un ejemplo de uso). Tenga en cuenta que mi implementación (con chain (), dada anteriormente) no es mucho peor: es cierto que crea todos los generadores len (iterables) en una vez ... pero NO crea todas las combinaciones de 2 ** len (iterables) a la vez, ya que, según tengo entendido, la cadena "usa" el primer generador antes de extraer de los siguientes.
Dan H
18

Este es un enfoque que puede transferirse fácilmente a todos los lenguajes de programación que admitan la recursión (sin itertools, sin rendimiento, sin comprensión de lista) :

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]]
Jonathan R
fuente
Ah! Buena implementación. Reconozco HEAD = a [0], TAIL = a [1:] de Prolog. O car = a [0], cdr = a [1:] de Lisp. Me pregunto si podríamos usar la memoria aquí ...
Javier Ruiz
Cierto. El corte de la lista es O (k) donde k es la longitud del corte. Supongo que uno podría acelerar esto haciendo una búsqueda en un mapa que lo haría O (1) en todas las ejecuciones, excepto en la primera. Sin embargo, tenga en cuenta que esta implementación no debe ser referenciada para el rendimiento. Para eso existen mejores implementaciones. Esta implementación es solo por simplicidad y portabilidad a la mayoría de los otros idiomas.
Jonathan R hace
14

Puede generar todas las combinaciones de una lista en Python usando este código simple

import itertools

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

El resultado sería:

[()]
[(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)]
saimadhu.polamuri
fuente
Error en este código: no devuelve el conjunto vacío. Puede significar xrange (0, ...) pero no lo he probado. editar : seguí adelante y edité tu respuesta para solucionarlo.
ninjagecko
13

Pensé que agregaría esta función para aquellos que buscan una respuesta sin importar itertools o cualquier otra biblioteca adicional.

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

Uso simple del generador de rendimiento:

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

Salida del ejemplo de uso anterior:

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


fuente
Creo que esta es una solución muy ordenada.
greentec
8

Aquí hay otra solución (una línea), que implica el uso de la itertools.combinationsfunción, pero aquí usamos una comprensión de lista doble (en oposición a un bucle for o sum):

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

Manifestación:

>>> 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)]
ninjagecko
fuente
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))

salida

[
 ['A'],
 ['B'],
 ['C'],
 ['A', 'B'],
 ['A', 'C'],
 ['B', 'C'],
 ['A', 'B', 'C']
]
Andrew Li
fuente
4

A continuación se muestra una "respuesta recursiva estándar", similar a la otra respuesta similar https://stackoverflow.com/a/23743696/711085 . (Realmente no tenemos que preocuparnos por quedarnos sin espacio en la pila ya que no hay forma de que podamos procesar todas las permutaciones de N!).

Visita cada elemento por turno, y lo toma o lo deja (podemos ver directamente la cardinalidad 2 ^ N de este 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],)

Manifestación:

>>> 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
ninjagecko
fuente
2

Usando la comprensión de la lista:

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 )

La salida sería:

['A', 'A']
['A', 'B']
['A', 'C']
['B', 'B']
['B', 'C']
['C', 'C']
zmk
fuente
44
Esta propuesta es hacer la secuencia de cadenas para construir conjuntos?!?! Santo cuervo .... Y: no está devolviendo el conjunto de poder, sino más bien, algo como combinaciones_con_remplazo (). (Ver docs.python.org/library/… )
Dan H
De hecho, esto hace lo mismo que combinación_con_remplazo () , pero al menos en mi caja, esto se ejecuta un poco más rápido que las herramientas iterto . ¿Qué puedo decir? Me gustan las comprensiones de listas.
zmk
1
¡Gracias por la respuesta! ¿Qué pasa con crear lista? Combinado con listas invertidas como ['A', 'A'], ['A', 'B'], ['A', 'C'], ['B', 'A'], [ 'B', 'B'], ['B', 'C'], ['C', 'A'], ['C', 'B'] y ['C', 'C'] que incluyen ¿todo?
Karyo
Muy interesante, pero mi python no es capaz de comprender las sutilezas aquí. ¿Hay algo especial en usar listCombined en diferentes ámbitos y el hecho de que el ciclo for está todo en una línea? Estoy tratando de portar esto a Java con poca suerte.
Scott Biggs
2

Este código emplea un algoritmo simple con listas anidadas ...

# 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()
Consejos
fuente
Entonces, lo que parece hacer este código es devolver [listOfCombinations, listOfCombinationsGroupedBySize]. Desafortunadamente, cuando se ejecuta con la entrada de demostración, proporciona 63 elementos en lugar de 64; parece faltar el conjunto vacío (en este caso, la cadena vacía "").
ninjagecko
2

Sé que es mucho más práctico usar itertools para obtener todas las combinaciones, pero puede lograr esto en parte con solo la comprensión de la lista si así lo desea, siempre que desee codificar mucho

Para combinaciones de dos pares:

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


Y, para combinaciones de tres pares, es tan fácil como esto:

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


El resultado es idéntico al uso de 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)]
Cynadyde
fuente
2

Sin usar 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']))
Pradeep Vairamani
fuente
2

Aquí hay dos implementaciones de itertools.combinations

Uno que devuelve una lista

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 devuelve un generador

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

Tenga en cuenta que se recomienda proporcionar una función auxiliar a aquellos porque el argumento de anteponer es estático y no cambia con cada llamada

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

Este es un caso muy superficial, pero es mejor prevenir que curar

Modar
fuente
2

Qué tal esto ... usó una cadena en lugar de una lista, pero lo mismo ... la cadena se puede tratar como una lista en 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)
Apurva Singh
fuente
2

Combinación de 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))

Gracias

Abhishek
fuente
2

Sin itertools Python 3 podrías hacer algo como esto:

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

donde inicialmente carry = "".

Laurynas Tamulevičius
fuente
2

3 funciones:

  1. lista de todas las combinaciones de n elementos
  2. todas las combinaciones de n elementos listan donde el orden no es distinto
  3. todas las permutaciones
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)
Alan Swindells
fuente
¡¡¡Esto me gusta mucho!!! ¡¡¡Gracias!!! Sin embargo, las funciones combinatorias de Python son un poco extrañas. En matemáticas, la función "combinaciones" sería Variaciones, y "combinacionesNoOrder" son en realidad combinaciones. Supongo que eso confunde a las personas que vienen a Python desde la rama de las matemáticas, como me pasó esta vez. De todos modos, una buena solución, ¡muchas gracias!
Đumić Branislav
1

Esta es mi implementación

    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
Andres Ulloa
fuente
1
¿Cuál es su implementación para resolver mejor que las implementaciones anteriores publicadas aquí?
user1767754
0

También puede usar la función powerset del excelente more_itertoolspaquete.

from more_itertools import powerset

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

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

También podemos verificar que cumple con los requisitos de OP

from more_itertools import ilen

assert ilen(powerset(range(15))) == 32_768
Jarno
fuente
-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
Anoop
fuente
1
Si tengo razón, este es el código exacto copiado de la documentación de Python [ docs.python.org/3.6/library/itertools.html ]. Si es así, por favor ref referencia la fuente.
GabrielChu
enfoque interesante
pelos
-1

Si alguien está buscando una lista inversa, como yo estaba:

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)
Expatriado C
fuente
-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')
Priyansh gupta
fuente