有用的代码使用reduce()?

cnu*_*cnu 120 python functional-programming

这里有没有人有任何有用的代码在python中使用reduce()函数?除了我们在示例中看到的通常的+和*之外,还有其他代码吗?

通过GvR 参考Python 3000中的reduce()命运

Cla*_*diu 64

除了+和*之外,我发现的其他用途与和和或,但现在我们已经anyall更换这些情况.

foldlfoldr在计划中提出了很多......

这是一些可爱的用法:

压平列表

目标:[[1, 2, 3], [4, 5], [6, 7, 8]]变成[1, 2, 3, 4, 5, 6, 7, 8].

reduce(list.__add__, [[1, 2, 3], [4, 5], [6, 7, 8]], [])
Run Code Online (Sandbox Code Playgroud)

数字的数字列表

目标:[1, 2, 3, 4, 5, 6, 7, 8]变成12345678.

丑陋,缓慢的方式:

int("".join(map(str, [1,2,3,4,5,6,7,8])))
Run Code Online (Sandbox Code Playgroud)

漂亮的reduce方式:

reduce(lambda a,d: 10*a+d, [1,2,3,4,5,6,7,8], 0)
Run Code Online (Sandbox Code Playgroud)

  • 为了展平列表,我更喜欢list(itertools.chain(*nested_list)) (22认同)
  • 总和([[1,2,3],[4,5],[6,7,8]],[]) (13认同)
  • 做一些基准测试,对于大型列表来说,"丑陋"的方式更快.`timeit.repeat('int("".join(map(str,digit_list)))',setup ='digit_list = list(d%10表示d in xrange(1,1000))',number = 1000) `timeit.repeat('reduce(lambda a,d:10*a + d,digit_list)',setup ='digit_list = list(d%10表示d in xrange(1,1000))',需要~0.09秒, number = 1000)`需要0.36秒(大约慢4倍).当列表变大时,基本乘以10变得昂贵,而对于str和连接的int保持便宜. (5认同)
  • 当然,对于小型列表(大小为10),则reduce方法快1.3倍.然而,即使在这种情况下,避免减少和做一个简单的循环甚至更快`timeit.repeat('convert_digit_list_to_int(digit_list)',setup ='digit_list = [d%10 for d in xrange(1,10)] \ndef convert_digit_list_to_int(digits):\ni = 0 \n表示数字为d:\ni = 10*i + d \n return i',number = 100000)`需要0.06秒,`timeit.repeat('reduce(lambda a, d:10*a + d,digit_list)',setup ='digit_list = list(d%10表示d in xrange(1,10))',number = 100000)`需要0.12 s并且将数字转换为str方法需要0.16秒. (3认同)
  • 它对按位运算也很有用.如果你想获取按位或一堆数字,例如,如果你需要将标志从列表转换为位掩码,该怎么办? (2认同)
  • 你正在调用最后一个简化示例吗?恕我直言,它还不错.对我来说int("".join(str(i)for i in range(1,9)))更具可读性. (2认同)

jfs*_*jfs 50

reduce()可用于查找3个或更多数字的最小公倍数:

#!/usr/bin/env python
from fractions import gcd
from functools import reduce

def lcm(*args):
    return reduce(lambda a,b: a * b // gcd(a, b), args)
Run Code Online (Sandbox Code Playgroud)

例:

>>> lcm(100, 23, 98)
112700
>>> lcm(*range(1, 20))
232792560
Run Code Online (Sandbox Code Playgroud)


jfs*_*jfs 38

reduce()可用于解析虚线名称(eval()使用起来太不安全):

>>> import __main__
>>> reduce(getattr, "os.path.abspath".split('.'), __main__)
<function abspath at 0x009AB530>
Run Code Online (Sandbox Code Playgroud)


sso*_*ler 23

找到N个给定列表的交集:

input_list = [[1, 2, 3, 4, 5], [2, 3, 4, 5, 6], [3, 4, 5, 6, 7]]

result = reduce(set.intersection, map(set, input_list))
Run Code Online (Sandbox Code Playgroud)

收益:

result = set([3, 4, 5])
Run Code Online (Sandbox Code Playgroud)

via:Python - 两个列表的交集


小智 12

我认为减少是一个愚蠢的命令.因此:

reduce(lambda hold,next:hold+chr(((ord(next.upper())-65)+13)%26+65),'znlorabggbbhfrshy','')
Run Code Online (Sandbox Code Playgroud)


mwe*_*den 11

reduce我在代码中找到的用法涉及到我有一些逻辑表达式的类结构的情况,我需要将这些表达式对象的列表转换为表达式的连接.我已经有了一个函数make_and来创建一个给出两个表达式的连接,所以我写了reduce(make_and,l).(我知道列表不是空的;否则它就像是reduce(make_and,l,make_true).)

这正是(某些)函数式程序员喜欢reduce(或折叠函数,因为这些函数通常被称为)的原因.经常有像已经有很多二元函数+,*,min,max,级联和,在我的情况,make_andmake_or.有一个reduce使得将这些操作提升到列表(或树或任何你得到的,一般的折叠函数)是微不足道的.

当然,如果sum经常使用某些实例(例如),那么你不想继续写作reduce.但是,不是sum使用一些for循环定义,而是可以轻松地定义它reduce.

其他人提到的可读性确实是一个问题.然而,你可以争辩说,只有人们发现reduce不那么"清晰"的原因是因为它不是许多人知道和/或使用的功能.


jfs*_*jfs 9

您可以替换value = json_obj['a']['b']['c']['d']['e']为:

value = reduce(dict.__getitem__, 'abcde', json_obj)
Run Code Online (Sandbox Code Playgroud)

如果您已将路径a/b/c/..作为列表.例如,使用列表中的项目更改嵌套dicts的dict中的值.


bea*_*rdc 8

功能组合:如果您已经有一系列要连续申请的功能,例如:

color = lambda x: x.replace('brown', 'blue')
speed = lambda x: x.replace('quick', 'slow')
work = lambda x: x.replace('lazy', 'industrious')
fs = [str.lower, color, speed, work, str.title]
Run Code Online (Sandbox Code Playgroud)

然后你可以连续应用它们:

>>> call = lambda s, func: func(s)
>>> s = "The Quick Brown Fox Jumps Over the Lazy Dog"
>>> reduce(call, fs, s)
'The Slow Blue Fox Jumps Over The Industrious Dog'
Run Code Online (Sandbox Code Playgroud)

在这种情况下,方法链可能更具可读性.但有时这是不可能的,这种组合可能比f1(f2(f3(f4(x))))一种语法更具可读性和可维护性.

  • 一个优点是您可以更改要在代码中应用的函数列表。 (2认同)

Eli*_*ght 7

@Blair Conrad:您还可以使用sum实现glob/reduce,如下所示:

files = sum([glob.glob(f) for f in args], [])
Run Code Online (Sandbox Code Playgroud)

这比你的两个例子中的任何一个都要简洁,完全是Pythonic,并且仍然只有一行代码.

因此,为了回答原始问题,我个人试图避免使用reduce,因为它从来没有真正必要,我发现它不如其他方法清晰.然而,有些人习惯于减少并更喜欢列出理解(尤其是Haskell程序员).但是,如果你还没有考虑减少问题,你可能不必担心使用它.

  • "sum"和"reduce"都会导致二次行为.它可以在线性时间内完成:[`files = chain.from_iterable(imap(iglob,args))`](http://stackoverflow.com/questions/15995/useful-code-which-uses-reduce-in-蟒蛇/ 282678#comment18841937_16091).虽然在这种情况下可能无关紧要,因为glob()访问磁盘需要时间. (2认同)

Jia*_*ian 6

reduce 可用于支持链式属性查找:

reduce(getattr, ('request', 'user', 'email'), self)
Run Code Online (Sandbox Code Playgroud)

当然,这相当于

self.request.user.email
Run Code Online (Sandbox Code Playgroud)

但是当您的代码需要接受任意属性列表时,它很有用.

(处理Django模型时,任意长度的链式属性都很常见.)


Jia*_*ian 5

reduce当您需要查找类似对象序列的并集或交集时,此功能非常有用set

>>> reduce(operator.or_, ({1}, {1, 2}, {1, 3}))  # union
{1, 2, 3}
>>> reduce(operator.and_, ({1}, {1, 2}, {1, 3}))  # intersection
{1}
Run Code Online (Sandbox Code Playgroud)

(除了实际的sets 之外,其中的一个例子是Django 的 Q 对象。)

另一方面,如果您正在处理bools,则应该使用anyand all

>>> any((True, False, True))
True
Run Code Online (Sandbox Code Playgroud)


Bre*_*dan 3

不确定这是否是您想要的,但您可以在 Google 上搜索源代码

点击链接在 Google Code 搜索中搜索“function:reduce() lang:python”

乍一看以下项目使用reduce()

  • 摩因摩因
  • 佐佩
  • 数字
  • 科学Python

等等,但这些并不奇怪,因为它们是巨大的项目。

reduce 的功能可以使用函数递归来完成,我猜 Guido 认为这更明确。

更新:

由于 Google 的代码搜索已于 2012 年 1 月 15 日停止,除了恢复到常规 Google 搜索之外,还有一个名为“代码片段集合”的东西看起来很有前途。这个(已关闭)问题的答案中提到了许多其他资源替代 Google 代码搜索?

更新 2(2017 年 5 月 29 日):

Nullege 搜索引擎是 Python 示例(开源代码)的一个很好的来源。

  • 此外,搜索reduce() 会产生在其代码中定义reduce 函数的项目。您应该搜索 lang:python "reduce(" 来查找内置函数的实际用法。 (2认同)