2012-03-07 11 views
5

He estado trabajando en algunos guiones rápidos y sucios para hacer algunos de mis deberes de química, y uno de ellos repite en listas de una longitud constante donde todos los elementos se suman a una constante dada. Para cada uno, verifico si cumplen con algunos criterios adicionales y los inserto en otra lista.Creando una matriz de números que suman un número dado

me di cuenta de una manera de cumplir con los criterios de suma, pero parece horrendo, y estoy seguro de que hay algún tipo de momento de aprendizaje aquí:

# iterate through all 11-element lists where the elements sum to 8. 
for a in range(8+1): 
for b in range(8-a+1): 
    for c in range(8-a-b+1): 
    for d in range(8-a-b-c+1): 
    for e in range(8-a-b-c-d+1): 
    for f in range(8-a-b-c-d-e+1): 
     for g in range(8-a-b-c-d-e-f+1): 
     for h in range(8-a-b-c-d-e-f-g+1): 
     for i in range(8-a-b-c-d-e-f-g-h+1): 
     for j in range(8-a-b-c-d-e-f-g-h-i+1): 
      k = 8-(a+b+c+d+e+f+g+h+i+j) 
      x = [a,b,c,d,e,f,g,h,i,j,k] 
      # see if x works for what I want 
+0

'[Vals Vals en itertools.product (rango (8), repita = 11) si suma (Vals) == 8]' es más bello, pero ** ** mucho más lento que su solución. – eumiro

+0

+1 - Apoyos para usar una computadora para automatizar sus tareas repetitivas de química. –

+0

Mi idea es la siguiente: para una lista de 11 enteros, todos sumando 8, MUCHOS de los números van a ser cero. Una manera rápida de hacer esto sería encontrar todas las formas de sumar enteros a 8 - por ejemplo '8, 1 + 7, 2 + 6, 3 + 5, 4 + 4, 1 + 1 + 6, 1 + 2 + 5 ... 'y luego permute aquellos con el número apropiado de ceros. –

Respuesta

1

Aquí hay un generador recursivo que genera las listas en orden lexicográfico. Al salir de exact como True se obtiene el resultado solicitado donde cada suma == límite; configuración exact a False proporciona todas las listas con 0 < = suma < = límite. La recursividad aprovecha esta opción para producir los resultados intermedios.

def lists_with_sum(length, limit, exact=True): 
    if length: 
     for l in lists_with_sum(length-1, limit, False): 
      gap = limit-sum(l) 
      for i in range(gap if exact else 0, gap+1): 
       yield l + [i] 
    else: 
     yield [] 
1

genérico, solución recursiva:

def get_lists_with_sum(length, my_sum): 
    if my_sum == 0: 
     return [[0 for _ in range(length)]] 

    if not length: 
     return [[]] 
    elif length == 1: 
     return [[my_sum]] 
    else: 
     lists = [] 
     for i in range(my_sum+1): 
      rest = my_sum - i 
      sublists = get_lists_with_sum(length-1, rest) 
      for sl in sublists: 
       sl.insert(0, i) 
       lists.append(sl) 

    return lists 

print get_lists_with_sum(11, 8) 
+0

Acabo de intentar ejecutar eso. Oh mi, eso es lento ... ¿Tal vez convertir a algo que utiliza una pila en lugar de recursión en toda regla? –

+0

Está dirigido a valores bajos, por supuesto. Para los números dados, creo que es aceptable. Crear un caché probablemente sea útil, porque los argumentos se repetirán con bastante frecuencia. Aún así, el número de combinaciones posibles explotará para argumentos de mayor valor. –

+0

Con argumentos '8,11', redirigió mi CPU durante unos minutos antes de que la matara. La respuesta de OP es realmente muy rápida (solo * fea *.) –

Cuestiones relacionadas