Supongamos que tengo el número 100 que necesito dividir en N partes, cada una de las cuales no debe exceder las 30 inicialmente. Entonces la agrupación inicial sería (30,30,30). El resto (que es 10) debe distribuirse entre estos tres grupos sumando 2 a cada grupo en sucesión, asegurando así que cada grupo sea un múltiplo de 2. Por lo tanto, el resultado deseado debería verse como (34,34,32).
Nota: El número original siempre es par.
Intenté resolver esto en Python y esto es lo que se me ocurrió. Claramente no está funcionando de la manera que pensé que lo haría. Distribuye el resto agregando 1 (y no 2, como se desea) iterativamente a cada grupo.
num = 100 parts = num//30 #Number of parts into which 'num' is to be divided def split(a, b): result = ([a//b + 1] * (a%b) + [a//b] * (b - a%b)) return(result) print(split(num, parts))Producción:
[34, 33, 33]Salida deseada:
[34, 34, 32] Primero, simplifiquemos su problema por un segundo. Olvídate de los múltiplos de 2. Imagina que quieres dividir un número n no necesariamente par en k partes no necesariamente pares.
Obviamente, la solución más equilibrada es que algunas partes sean n // k , y algunas partes sean n // k + 1 .
¿Cuántos de los cuales? Llamemos r al número de partes con n // k + 1 . Entonces hay k - r partes con n // k , y todas las partes suman:
(n // k) * (k - r) + (n // k + 1) * r == (n // k) * (k - r) + (n // k) * r + r == (n // k) * (k - r + r) + r == (n // k) * k + r Pero las partes deben sumar n , por lo que necesitamos encontrar r tal que:
n == (n // k) * k + r Felizmente, podría reconocer aquí la división euclidiana, siendo n // k el cociente y r el resto.
Esto nos da nuestra función split :
def split(n, k): d,r = divmod(n, k) return [d+1]*r + [d]*(kr)Pruebas:
print( split(50, 3) ) # [17, 17, 16] Ahora volvamos a tu problema split_even . Ahora que tenemos la función genérica split , una forma simple de resolver split_even es usar split :
def split_even(n, k): return [2 * x for x in split(n // 2, k)]Pruebas:
print( split_even(100, 3) ) # [34, 34, 32]m Es trivial hacer lo mismo con múltiplos de un número m distinto de 2:
def split_multiples(n, k, m=2): return [m * x for x in split(n // m, k)]Pruebas:
print( split_multiples(102, 4, 3) ) # [27, 27, 24, 24]Mi enfoque aquí es crear tres matrices y sumarlas, las dos primeras son simples, pero la última es un poco más compleja de seguir: es solo repetir 2 (por) tantas veces como sea posible dado el resto, luego repetir 0s.
# Part 1 np.repeat(first, x//first) # Part 2 np.repeat(by, x//first) # Part 3 np.repeat([by, 0], [(x//first) - ((x - (x//first*first)) // by % by), (x - (x//first*first)) // by % by])Envuelto en una función:
def split(x, first, by): return(np.repeat(first, x//first) + np.repeat(by, x//first) + np.repeat([by, 0], [(x//first) - ((x - (x//first*first)) // by % by), (x - (x//first*first)) // by % by])) split(100, 30, 2)Esta solución no es muy clara y fácil de seguir, pero no necesita bucles.
Código completo:
def split(a,b): lower = (a//b//2) * 2 num = a % (b*2) // 2 return [lower + 2] * num + [lower] * (b - num)Explicación:
value // parts ) al siguiente valor par ( (x // 2) * 2 )a en el doble de partes y lo dividimos por dos para compensar la multiplicaciónlower + 2 veces el número calculado de valores más altos y los números más bajos están llenando los otros espacios