Autant que je sache, la fonction de réduction prend une liste l
et une fonction f
. Ensuite, il appelle la fonction f
sur les deux premiers éléments de la liste, puis appelle à plusieurs reprises la fonction f
avec l'élément de liste suivant et le résultat précédent.
Donc, je définis les fonctions suivantes:
La fonction suivante calcule la factorielle.
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)
Cela ne devrait-il pas me donner ((1! * 3!) * 1!) = 6
? Mais au lieu de cela, il donne 720
. Pourquoi 720
? Il semble prendre aussi la factorielle de 6
. Mais j'ai besoin de comprendre pourquoi.
Quelqu'un peut-il expliquer pourquoi cela se produit et une solution de contournement?
En gros, je souhaite calculer le produit des factorielles de toutes les entrées de la liste . Le plan de sauvegarde consiste à exécuter une boucle et à la calculer. Mais, je préférerais utiliser réduire.
Ok, compris
Je dois d'abord mapper les nombres sur leurs factorielles, puis appeler réducteur avec multiplicateur.
Donc, cela fonctionnerait:
lst_fact = map(fact, lst)
reduce(operator.mul, lst_fact)
Le moyen le plus simple de comprendre reduction () est de regarder son code pur équivalent en Python:
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
Vous pouvez voir que cela n’a de sens que pour reduction_func () d’appliquer la factorielle à l’argument le plus à droite:
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)
Avec cette petite révision, le code produit 6 comme vous le souhaitiez :-)
Votre fonction appelle fact()
sur les deux arguments . Vous calculez ((1! * 3!)! * 1!)
. La solution de contournement consiste à l'appeler uniquement sur le deuxième argument et à transmettre à reduce()
une valeur initiale de 1.
De la documentation Python reduce
,
réduire (fonction, séquence) renvoie une valeur unique construite en appelant la fonction (binaire) sur les deux premiers éléments de la séquence, puis sur le résultat et sur l'élément suivant, etc.
Alors, traversant. Il calcule reduce_func
des deux premiers éléments, reduce_func(1, 3) = 1! * 3! = 6
. Ensuite, il calcule reduce_func
du résultat et l'élément suivant: reduce_func(6, 1) = 6! * 1! = 720
.
Vous avez raté cela. Lorsque le résultat du premier appel reduce_func
est transmis en entrée au second, il est factorisé avant la multiplication.
Tout d’abord, votre reduce_func
n’a pas la structure d’un pli; cela ne correspond pas à votre description d'un pli (ce qui est correct).
La structure d'un pli est la suivante: def foldl(func, start, iter): return func(start, foldl(func, next(iter), iter)
Maintenant, votre fonction fact
ne fonctionne pas sur deux éléments - elle calcule simplement factorielle.
Donc, en résumé, vous n'utilisez pas un pli et avec cette définition de factorielle, vous n'en avez pas besoin.
Si vous voulez jouer avec factorial, jetez un œil au combinateur y: http://mvanier.livejournal.com/2897.html
Si vous voulez en savoir plus sur les plis, regardez ma réponse à cette question, qui montre son utilisation pour calculer des fractions cumulatives: création d'un pourcentage cumulatif à partir d'un dictionnaire de données
Vous pouvez également implémenter factorielle en utilisant réduire.
def factorial(n):
return(reduce(lambda x,y:x*y,range(n+1)[1:]))
Réduire exécute la fonction du paramètre n ° 1 successivement à l'aide des valeurs fournies par l'itérateur dans le paramètre n ° 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)