这里有人有用Python中reduce()函数的有用代码吗?除了我们在示例中看到的常规的+和*之外,还有其他的代码吗?
这里有人有用Python中reduce()函数的有用代码吗?除了我们在示例中看到的常规的+和*之外,还有其他的代码吗?
any
和 all
来替代这些情况。foldl
和 foldr
经常出现...[[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]], [])
将数字列表转换为数字
目标:将[1, 2, 3, 4, 5, 6, 7, 8]
转换为12345678
。
低效、繁琐的方式:
int("".join(map(str, [1,2,3,4,5,6,7,8])))
简洁的 reduce
方法:
reduce(lambda a,d: 10*a+d, [1,2,3,4,5,6,7,8], 0)
timeit.repeat('int("".join(map(str, digit_list)))', setup = 'digit_list = list(d%10 for d in xrange(1,1000))', number=1000)
需要约0.09秒,而timeit.repeat('reduce(lambda a,d: 10*a+d, digit_list)', setup = 'digit_list = list(d%10 for d in xrange(1,1000))', number=1000)
需要0.36秒(大约慢4倍)。基本上,当列表变得大时,乘以10会变得昂贵,而int转换为str和连接则保持廉价。 - dr jimbobtimeit.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):\n i = 0\n for d in digits:\n i = 10*i + d\n return i', number=100000)
需要0.06 s,timeit.repeat('reduce(lambda a,d: 10*a+d, digit_list)', setup = 'digit_list = list(d%10 for d in xrange(1,10))', number=100000)
需要0.12 s,将数字转换为字符串的方法需要0.16 s。 - dr jimbobreduce()
可以用来找到3个或更多数字的最小公倍数:
#!/usr/bin/env python
from math import gcd
from functools import reduce
def lcm(*args):
return reduce(lambda a,b: a * b // gcd(a, b), args)
示例:
>>> lcm(100, 23, 98)
112700
>>> lcm(*range(1, 20))
232792560
可以使用reduce()
解析点分名称(当使用eval()
不安全时):
>>> import __main__
>>> reduce(getattr, "os.path.abspath".split('.'), __main__)
<function abspath at 0x009AB530>
__main__
是一个代表你想要获取属性的对象的替身。在这个例子中,它是一个模块对象(repl执行的当前模块)。只要它具有所需的属性,它可以是任何你喜欢的对象。 - jfs查找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))
返回:
result = set([3, 4, 5])
我认为reduce命令很傻。因此:
reduce(lambda hold,next:hold+chr(((ord(next.upper())-65)+13)%26+65),'znlorabggbbhfrshy','')
函数组合:如果您已经有了一系列希望按顺序应用的函数,例如:
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]
然后,您可以依次应用它们:
>>> 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'
在这种情况下,方法链可能更易读。但有时不可能使用方法链,这种组合方式可能比 f1(f2(f3(f4(x))))
这种语法更易读且更易维护。
reduce
函数,它用于将逻辑表达式的类结构体列表转换为这些表达式的并集。我已经有一个make_and
函数,可以将两个表达式合并为一个,并且我写了reduce(make_and, l)
来实现这一点。(我知道列表不为空;否则就要像reduce(make_and,l,make_true)
那样处理。)reduce
(或通常被称为“fold”函数的函数)的原因之一。通常已经有许多像+
、*
、min
、max
、连接以及在我的情况下的make_and
和make_or
这样的二元函数。拥有reduce
函数可以轻松将这些操作提升到列表(或树等其他任何结构,对于折叠函数而言)。sum
)经常使用,那么您不想一直编写reduce
。但是,与其使用某些for循环定义sum
,不如使用reduce
同样容易地定义它。reduce
不太“清晰”的唯一原因是这不是很多人知道和/或使用的函数。and
运算符的短路行为:L and reduce(make_and, L)
如果在这种情况下返回空列表是适当的。 - jfs您可以使用以下代码替换 value = json_obj['a']['b']['c']['d']['e']
:
value = reduce(dict.__getitem__, 'abcde', json_obj)
a/b/c/.. 作为列表存在。例如,使用列表中的项更改嵌套字典的值。
@Blair Conrad:你也可以使用sum来实现你的glob/reduce,代码如下:
files = sum([glob.glob(f) for f in args], [])
这种方法比你提供的两个例子都更简洁,完全符合Python风格,而且仍然只有一行代码。
所以,回答原始问题,我个人尽量避免使用reduce,因为它从来不是真正必要的,而且我发现它比其他方法不太清晰。然而,有些人习惯于使用reduce,并且更喜欢它而不是列表推导式(尤其是Haskell程序员)。但如果你还没有考虑过用reduce解决问题,那么你可能不需要担心使用它。
sum
和reduce
都会导致二次行为。可以在线性时间内完成:files = chain.from_iterable(imap(iglob, args))
。虽然由于glob()访问磁盘所需的时间,这在本例中可能并不重要。 - jfsreduce
可以用于支持链式属性查找:
reduce(getattr, ('request', 'user', 'email'), self)
self.request.user.email
from functools import reduce
允许相同的代码在 Python 2 和 3 上运行。 - jfs