python list functional-programming reduce fold

python reduce



¿Cuál es el equivalente "pythonic" de la función funcional de "fold"? (6)

En Python 3, se ha eliminado la reduce : notas de la versión . Sin embargo, puedes usar el módulo functools

import operator, functools def product(xs): return functools.reduce(operator.mul, xs, 1)

Por otro lado, la documentación expresa preferencia hacia -loop en lugar de reduce , por lo tanto:

def product(xs): result = 1 for i in xs: result *= i return result

¿Cuál es la forma más idiomática de lograr algo como lo siguiente, en Haskell:

foldl (+) 0 [1,2,3,4,5] --> 15

O su equivalente en Ruby:

[1,2,3,4,5].inject(0) {|m,x| m + x} #> 15

Obviamente, Python proporciona la función de reduce , que es una implementación de fold, exactamente como la anterior, sin embargo, me dijeron que la forma "pitthonic" de programación era evitar términos lambda y funciones de orden superior, prefiriendo listas de comprensión cuando sea posible. Por lo tanto, ¿existe una forma preferida de doblar una lista, o una estructura tipo lista en Python que no sea la función de reduce , o se reduce la forma idiomática de lograr esto?


Haskell

foldl (+) 0 [1,2,3,4,5]

Pitón

reduce(lambda a,b: a+b, [1,2,3,4,5], 0)

Obviamente, ese es un ejemplo trivial para ilustrar un punto. En Python simplemente harías la sum([1,2,3,4,5]) e incluso los puristas de Haskell generalmente preferirían la sum [1,2,3,4,5] .

Para escenarios no triviales cuando no hay una función de conveniencia obvia, el enfoque idiotático pitónico es escribir explícitamente el bucle for y usar una asignación de variable mutable en lugar de usar reduce o fold .

Ese no es en absoluto el estilo funcional, pero esa es la forma "pitónica". Python no está diseñado para puristas funcionales. Vea cómo Python está a favor de las excepciones para el control de flujo para ver cómo es la pitón idiomática no funcional.


La forma Pythonic de sumar una matriz es sum . Para otros fines, a veces puede usar alguna combinación de reduce y el módulo de operator , por ejemplo

def product(xs): return reduce(operator.mul, xs, 1)

Tenga en cuenta que reduce es en realidad un foldl , en términos de Haskell. No hay una sintaxis especial para realizar pliegues, no hay foldr incorporado y, en realidad, usar reduce con operadores no asociativos se considera un mal estilo.

Usar funciones de orden superior es bastante pitónico; hace buen uso del principio de Python de que todo es un objeto, incluidas funciones y clases. Tienes razón en que los lambdas son mal vistos por algunos pitonistas, pero sobre todo porque tienden a no ser muy legibles cuando se vuelven complejos.


La respuesta real a este problema (reducir) es: ¡solo use un bucle!

initial_value = 0 for x in the_list: initial_value += x #or any function.

Esto será más rápido que un reductor y cosas como PyPy pueden optimizar bucles como ese.

Por cierto, el caso de suma debe ser resuelto con la función sum


Puedes reinventar la rueda también:

def fold(f, l, a): """ f: the function to apply l: the list to fold a: the accumulator, who is also the ''zero'' on the first call """ return a if(len(l) == 0) else fold(f, l[1:], f(a, l[0])) print "Sum:", fold(lambda x, y : x+y, [1,2,3,4,5], 0) print "Any:", fold(lambda x, y : x or y, [False, True, False], False) print "All:", fold(lambda x, y : x and y, [False, True, False], True) # Prove that result can be of a different type of the list''s elements print "Count(x==True):", print fold(lambda x, y : x+1 if(y) else x, [False, True, True], 0)


Realmente no responden a la pregunta, sino frases sencillas para foldl y foldr:

a = [8,3,4] ## Foldl reduce(lambda x,y: x**y, a) #68719476736 ## Foldr reduce(lambda x,y: y**x, a[::-1]) #14134776518227074636666380005943348126619871175004951664972849610340958208L