¿Hacer una combinación de coeficientes para un rango?

Tengo problemas para hacer una combinación de coeficientes. Básicamente, tengo una lista de elementos y quiero obtener todas las combinaciones únicas de coeficientes para ellos de esta manera:

dog:1 cat:1
dog:2 cat:1
dog:3 cat:1
dog:1 cat:2
dog:2 cat:2

No estoy realmente seguro de cuál es la mejor manera de hacer esto (programación dinámica, recursión, fuerza bruta, etc.), así que intenté comenzar haciendo una recursión:

list = ["dog", "cat"]

coeff = [1] * len(list)
main_queue = []

def recursion(k, list):
    for item in list[0:k-1]:
        for data in range(5):
            coeff_temp = coeff
            coeff_temp[k] = data
            main_queue.append(coeff_temp)
            #print item, data

    if k == (len(list)-1):
        return
    else:
        recursion(k+1, list)

recursion(0, list)

print "*" * 30

for x in main_queue:
    print x

la salida es:

******************************
[4, 1]
[4, 1]
[4, 1]
[4, 1]
[4, 1]

Solo cambia la última entrada en la cola principal que hice. ¿Qué estoy haciendo mal?

p.d. ¿Es esta la mejor manera de hacer esto (el rango es entre 1 y 5 y habrá entre 20 y 30 elementos en la lista... es mejor usar la programación dinámica)?

preguntado el 22 de mayo de 12 a las 17:05

No entiendo de su descripción lo que está tratando de lograr. -

Por favor podría proporcionar un completar ejemplo que especificaría claramente la entrada y la salida esperada. -

@ murgatroid99 Tengo un ejemplo de la salida prevista... ¿Qué parte tiene problemas para entender? -

No veo la conexión entre la entrada dada, su descripción de su objetivo y la salida dada. Y la salida real es tan diferente que no parece estar relacionada. -

I pensar quiere todas las combinaciones de 0 a 4 perros, 0 a 4 gatos, 0 a 4 monos, etc. -

5 Respuestas

data = ["dog", "cat"]
upto = 4

def all_combos(items, upto):
    if items < 1:
        yield []
    else:
        for r in range(upto+1):
            for rest in all_combos(items-1, upto):
                yield [r] + rest

for coeffs in all_combos(len(data), upto):
    print ", ".join("{}s: {}".format(n, coeff) for n,coeff in zip(data,coeffs))

resultados en

dogs: 0, cats: 0
dogs: 0, cats: 1
dogs: 0, cats: 2
dogs: 0, cats: 3
dogs: 0, cats: 4
dogs: 1, cats: 0
dogs: 1, cats: 1
dogs: 1, cats: 2
dogs: 1, cats: 3
dogs: 1, cats: 4
dogs: 2, cats: 0
dogs: 2, cats: 1
dogs: 2, cats: 2
dogs: 2, cats: 3
dogs: 2, cats: 4
dogs: 3, cats: 0
dogs: 3, cats: 1
dogs: 3, cats: 2
dogs: 3, cats: 3
dogs: 3, cats: 4
dogs: 4, cats: 0
dogs: 4, cats: 1
dogs: 4, cats: 2
dogs: 4, cats: 3
dogs: 4, cats: 4

que es lo que buscas. Ten en cuenta que el número de combinaciones será (len(data))**upto que aumenta explosivamente a medida que los datos y hasta crecen.

Edit: como se ha señalado, otra forma de lograrlo es

from itertools import product

def all_combos(items, upto):
    return product(*(range(upto+1) for i in range(items)))

contestado el 22 de mayo de 12 a las 18:05

No lo haria itertools.product ser una forma más sencilla de obtener esta salida? (Comparto la confusión general sobre lo que quiere el OP; el ejemplo dado no coincide con sus comentarios posteriores). DSM

@DSM: Definitivamente. Vea mi respuesta para saber cómo usarlo. - Eric

Tu error es esta línea:

coeff_temp = coeff

Eso no hace una copia de coeff: que hace referencia al mismo objeto. Cuando lo modificas en la siguiente línea:

coeff_temp[k] = data

Está modificando todos los que ha insertado hasta ahora: ¡todos son la misma lista!

Para copiar realmente la lista, use:

coeff_temp = list(coeff)

or

coeff_temp = coeff[:]

Aquí está la mejor solución a su problema:

import itertools
data = {
    "dog": xrange(1, 5),
    "cat": xrange(1, 5)
    #add more here...
}
combinations = (dict(zip(data.keys(), c)) for c in itertools.product(*data.values()))

for c in combinations:
    print c

contestado el 22 de mayo de 12 a las 17:05

Gracias Eric, me di cuenta de que también cometí otro error. Usé list como variable, así que usé tu ejemplo y cambié el nombre de la variable, pero ahora aparece un error. TypeError: 'type' object is not iterable en el primer bucle for en la función de recursión - Alma perdida

@Error_404 Entonces todavía estás usando list como variable. - Eric

tienes razón, hubo una instancia que me perdí. Parece que funciona ahora, pero hay resultados duplicados. - Alma perdida

@Error_404: Eche otro vistazo. Lo hice genérico - Eric

Acabo de darme cuenta de eso... gracias. Y gracias por tu respuesta/ayuda. - Alma perdida

Me parece que lo que desea es un número de base M de N dígitos, donde N es la cantidad de elementos en la lista y M es la cantidad de valores posibles para cada uno.

Solo por ejemplo, si tuviera 3 elementos en la lista y quisiera valores del 1 al 4 para cada uno, usaría un número de base 3 de 3 dígitos. Como tu primer dígito es 1, agregaría uno a cada dígito a medida que lo asigna al elemento de la lista.

En esto, la primera columna es el número real a medida que cuentas, y la segunda columna es el mismo número con 1 agregado a cada dígito, luego los valores asignados a cada uno de los tres animales:

000   111     cat 1 dog 1 hamster 1
001   112     cat 1 dog 1 hamster 2
002   113     cat 1 dog 1 hamster 3
010   121     cat 1 dog 2 hamster 1
011   122     cat 1 dog 2 hamster 2
012   123     cat 1 dog 2 hamster 3
020   131     cat 1 dog 3 hamster 1
021   132     cat 1 dog 3 hamster 2
022   133     cat 1 dog 3 hamster 3
100   211     cat 2 dog 1 hamster 1

y así sucesivamente para los números restantes de base 3 de 3 dígitos.

contestado el 22 de mayo de 12 a las 17:05

Intenta ver itertools lib http://docs.python.org/library/itertools.html donde puede encontrar la función combinaciones (), debe ayudarlo.

contestado el 22 de mayo de 12 a las 17:05

Si desea combinaciones, la recursividad es la respuesta correcta casi todo el tiempo.

Hay un problema con tu código: Dentro del recursion función, cuando dices coeff_temp = coeff estás copiando el referencia a coeff, por lo que solo está agregando la misma lista cada vez. Es por eso . De lo contrario, el método me parece bien.

Cambiar la linea

coeff_temp = coeff

a

coeff_temp = list(coeff)

para copiar la lista y continuar desde allí.

El módulo itertools es una buena solución para combinaciones.

contestado el 23 de mayo de 12 a las 19:05

Lo siento, @Eric ya respondió este mismo problema mientras escribía mi respuesta, así que no la vi hasta que la publiqué. El crédito debe ser para él. - Alejandro Piad

Llegaste primero, mientras yo estaba escribiendo, mira los tiempos. Sin embargo, su razonamiento es incorrecto: el hecho de que coeff es global es irrelevante. - Eric

@Eric: Seguramente mi explicación no fue lo suficientemente clara. Estaba tratando de decir exactamente lo mismo que tú, que estaba usando una referencia a la misma lista. Ahora veo que no está muy claro, y lo he arreglado. Gracias por el comentario. - Alejandro Piad

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.