python函数式编程for_python - 与函数式编程中的'fold'函数等效的'pythonic'是什么?...

python - 与函数式编程中的'fold'函数等效的'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术语和高阶函数,尽可能选择列表推导。 因此,有没有一种首选的方法来折叠Python中的列表或类似列表的结构,而不是reduce函数,或者是reduce实现这一目的的惯用方法?

9个解决方案

105 votes

Pythonic对数组求和的方法是reduce.对于其他目的,有时可以使用foldl和foldr模块的某种组合,例如:

def product(xs):

return reduce(operator.mul, xs, 1)

请注意,2474159433223472128实际上是foldl,用Haskell术语表示。 没有特殊的语法来执行折叠,没有内置foldr,实际上使用reduce与非关联运算符被认为是坏样式。

使用高阶函数是相当pythonic; 它充分利用了Python的原则,即一切都是一个对象,包括函数和类。 你是对的,一些Python会员不赞同lambdas,但主要是因为当它们变得复杂时它们往往不具有可读性。

Fred Foo answered 2019-07-22T12:49:55Z

15 votes

哈斯克尔

reduce

蟒蛇

reduce

显然,这是一个简单的例子来说明一个观点。 在Python中你只需做reduce甚至Haskell纯粹主义者通常会更喜欢fold。

对于没有明显的便利函数的非平凡场景,惯用的pythonic方法是明确地写出for循环并使用可变变量赋值而不是使用reduce或fold。

这根本不是功能风格,但那是“pythonic”方式。 Python不是为功能纯粹主义者设计的。 了解Python如何支持流控制的异常,以了解非功能性的idiomatic python是如何实现的。

clay answered 2019-07-22T12:50:56Z

11 votes

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

import operator, functools

def product(xs):

return functools.reduce(operator.mul, xs, 1)

另一方面,文档表达了对for-loop而不是reduce的偏好,因此:

def product(xs):

result = 1

for i in xs:

result *= i

return result

Kyr answered 2019-07-22T12:51:33Z

4 votes

你也可以重新发明轮子:

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)

Zenobe answered 2019-07-22T12:52:00Z

4 votes

不是真的回答这个问题,而是用于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

Mehdi Nellen answered 2019-07-22T12:52:28Z

2 votes

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

initial_value = 0

for x in the_list:

initial_value += x #or any function.

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

顺便说一句,总和案例应该用sum函数来解决

JBernardo answered 2019-07-22T12:53:10Z

1 votes

我可能很晚才参加派对,但我们可以使用简单的lambda演算和curried函数创建自定义15。 这是我在python中实现的foldr。

def foldr(func):

def accumulator(acc):

def listFunc(l):

if l:

x = l[0]

xs = l[1:]

return func(x)(foldr(func)(acc)(xs))

else:

return acc

return listFunc

return accumulator

def curried_add(x):

def inner(y):

return x + y

return inner

def curried_mult(x):

def inner(y):

return x * y

return inner

print foldr(curried_add)(0)(range(1, 6))

print foldr(curried_mult)(1)(range(1, 6))

即使实现是递归的(可能很慢),它也将分别打印值15和120

Pant answered 2019-07-22T12:53:49Z

1 votes

从Python 3.8开始,并引入赋值表达式(PEP 572)(items运算符),它可以命名表达式的结果,我们可以使用列表解析来复制其他语言称为fold / foldleft / reduce运算的内容:

给定一个列表,一个reduce函数和一个累加器:

items = [1, 2, 3, 4, 5]

f = lambda acc, x: acc * x

accumulator = 1

我们可以用f折叠items以获得结果accumulation:

[accumulator := f(accumulator, x) for x in items]

# accumulator = 120

或以浓缩形式:

acc = 1; [acc := acc * x for x in [1, 2, 3, 4, 5]]

# acc = 120

请注意,这实际上也是一个“scanleft”操作,因为列表理解的结果表示每个步骤的累积状态:

acc = 1

scanned = [acc := acc * x for x in [1, 2, 3, 4, 5]]

# scanned = [1, 2, 6, 24, 120]

# acc = 120

Xavier Guihot answered 2019-07-22T12:54:57Z

0 votes

我相信这个问题的一些受访者已经错过了fold功能作为抽象工具的更广泛的含义。 是的,sum可以为整数列表做同样的事情,但这是一个微不足道的案例。 fold更通用。 当您拥有一系列不同形状的数据结构并希望干净地表达聚合时,它非常有用。 因此,不必每次都使用聚合变量构建一个for循环并手动重新计算它,fold函数(或者Python版本,reduce似乎对应)允许程序员更明确地表达聚合的意图 只需提供两件事:

聚合的默认起始值或“种子”值。

获取聚合的当前值(以“种子”开头)和列表中的下一个元素的函数,并返回下一个聚合值。

rq_ answered 2019-07-22T12:55:46Z

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值