python - from - ¿Cómo funciona la función reducir?
python zip (8)
Por lo que yo entiendo, la función de reducción toma una lista l
y una función f
. Luego, llama a la función f
en los primeros dos elementos de la lista y luego llama repetidamente a la función f
con el siguiente elemento de lista y el resultado anterior.
Entonces, defino las siguientes funciones:
La siguiente función calcula el factorial.
def fact(n):
if n == 0 or n == 1:
return 1
return fact(n-1) * n
def reduce_func(x,y):
return fact(x) * fact(y)
lst = [1, 3, 1]
print reduce(reduce_func, lst)
Ahora, ¿no debería esto darme ((1! * 3!) * 1!) = 6
? Pero, en cambio da 720
. ¿Por qué 720
? Parece tomar el factorial de 6
también. Pero, necesito entender por qué.
¿Alguien puede explicar por qué sucede esto y una solución alternativa?
Básicamente quiero calcular el producto de factoriales de todas las entradas en la lista. El plan de copia de seguridad es ejecutar un bucle y computarlo. Pero, preferiría usar reducir.
Bueno, primero que todo, su reduce_func
no tiene la estructura de un pliegue; no coincide con su descripción de un pliegue (que es correcto).
La estructura de un pliegue es: def foldl(func, start, iter): return func(start, foldl(func, next(iter), iter)
Ahora, su función de fact
no opera en dos elementos, solo calcula factorial.
Entonces, en resumen, no está utilizando un pliegue, y con esa definición de factorial, no necesita hacerlo.
Si quieres jugar con factorial, echa un vistazo al combinador de y: http://mvanier.livejournal.com/2897.html
Si desea obtener información sobre los pliegues, mire mi respuesta a esta pregunta, que demuestra su uso para calcular fracciones acumulativas: crear un porcentaje acumulativo a partir de un diccionario de datos
Desde el Python reduce
documentación ,
reduce (función, secuencia) devuelve un solo valor construido llamando a la función (binaria) en los dos primeros elementos de la secuencia, luego en el resultado y el siguiente elemento, y así sucesivamente.
Entonces, paso a través. Calcula reduce_func
de los primeros dos elementos, reduce_func(1, 3) = 1! * 3! = 6
reduce_func(1, 3) = 1! * 3! = 6
reduce_func(1, 3) = 1! * 3! = 6
. Luego, calcula reduce_func
del resultado y el siguiente elemento: reduce_func(6, 1) = 6! * 1! = 720
reduce_func(6, 1) = 6! * 1! = 720
reduce_func(6, 1) = 6! * 1! = 720
.
Te perdiste eso, cuando el resultado de la primera llamada reduce_func
se pasa como entrada al segundo, se factoriza antes de la multiplicación.
La forma más fácil de entender reduce () es mirar su código equivalente de Python puro:
def myreduce(func, iterable, start=None):
it = iter(iterable)
if start is None:
try:
start = next(it)
except StopIteration:
raise TypeError(''reduce() of empty sequence with no initial value'')
accum_value = start
for x in iterable:
accum_value = func(accum_value, x)
return accum_value
Puedes ver que solo tiene sentido que tu reduce_func () aplique el factorial al argumento más a la derecha:
def fact(n):
if n == 0 or n == 1:
return 1
return fact(n-1) * n
def reduce_func(x,y):
return x * fact(y)
lst = [1, 3, 1]
print reduce(reduce_func, lst)
Con esa pequeña revisión, el código produce 6 como esperabas :-)
Ok lo tengo:
Necesito asignar los números a sus factoriales primero y luego llamar a reducir con el operador multiplicar.
Entonces, esto funcionaría:
lst_fact = map(fact, lst)
reduce(operator.mul, lst_fact)
Reducir ejecuta la función en el parámetro # 1 sucesivamente a través de los valores proporcionados por el iterador en el parámetro # 2
print ''-------------- Example: Reduce(x + y) --------------''
def add(x,y): return x+y
x = 5
y = 10
import functools
tot = functools.reduce(add, range(5, 10))
print ''reduce(''+str(x)+'',''+str(y)+'')='' ,tot
def myreduce(a,b):
tot = 0
for i in range(a,b):
tot = tot+i
print i,tot
print ''myreduce(''+str(a)+'',''+str(b)+'')='' ,tot
myreduce(x,y)
print ''-------------- Example: Reduce(x * y) --------------''
def add(x,y): return x*y
x = 5
y = 10
import functools
tot = functools.reduce(add, range(5, 10))
print ''reduce(''+str(x)+'',''+str(y)+'')='' ,tot
def myreduce(a,b):
tot = 1
for i in range(a,b):
tot = tot * i
print i,tot
print ''myreduce(''+str(a)+'',''+str(b)+'')='' ,tot
myreduce(x,y)
Su función llama a fact()
en ambos argumentos . Estás calculando ((1! * 3!)! * 1!)
. La solución es solo invocarlo solo en el segundo argumento y pasar a reduce()
un valor inicial de 1.
También podrías implementar factorial utilizando reducir.
def factorial(n):
return(reduce(lambda x,y:x*y,range(n+1)[1:]))