什么是函数式编程的“折叠”函数的“pythonic”?

在Haskell中实现类似以下内容的最习惯的方法是什么:

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

或者在Ruby中相当于:

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

很明显,Python提供了reduce函数,这是fold的一个实现,正如上面那样,但是我被告知,pythonic的编程方式是避免lambda项和高阶函数,在可能的情况下更喜欢list-comprehensions。 因此,是否有一种在Python中不是reduce函数的列表或列表结构的优选方式,还是reduce了实现这种方式的惯用方式?

总结一个数组的Pythonic方法是sum 。 为了其他目的,有时可以使用reduceoperator模块的一些组合,例如

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

请注意,在Haskell中, reduce实际上是一个foldl 。 没有特别的语法来执行折叠,没有内置的折叠器,而实际上使用非关联运算符的foldr被认为是不好的风格。

使用高阶函数是相当pythonic; 它充分利用了Python的原则,即一切都是一个对象,包括函数和类。 你是对的,lambda被一些Pythonistas皱起了眉头,但主要是因为它们在变得复杂的时候往往不易读。

哈斯克尔

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

python

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

显然,这是一个微不足道的例子来说明一个观点。 在Python中,你只需要sum([1,2,3,4,5]) ,甚至Haskell纯粹主义者通常更喜欢sum [1,2,3,4,5]

对于不存在明显的方便函数的非平凡场景,惯用的pythonic方法是明确地写出for循环,并使用可变variables赋值而不是使用reducefold

这根本不是function性的风格,但那是“pythonic”方式。 Python不是为function纯粹主义者devise的。 了解Python如何利用stream控制的exception来了解非function性惯用python是如何实现的。

在Python 3中, reduce已被删除: 发行说明 。 不过你可以使用functools模块

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

另一方面,文件表示优先selectfor -loop而不是reduce ,因此:

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

你也可以重新发明轮子:

 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) 

这个(减less)问题的实际答案是:只要使用一个循环!

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

这将比缩减更快,像PyPy这样的东西可以优化循环。

顺便说一下,和情况应该用sum函数来解决

没有真正回答这个问题,但foldl和foldr的一行:

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