Useful code which uses reduce()?
这里有没有人有在python中使用reduce()函数的有用代码?除了我们在示例中看到的通常的+和*之外,还有其他代码吗?
用gvr引用python 3000中reduce()的命运
除了+和*之外,我发现它的其他用途是和和或,但现在我们有了
以下是一些可爱的用法:
把名单弄平
目标:把
1 | reduce(list.__add__, [[1, 2, 3], [4, 5], [6, 7, 8]], []) |
数字到数字的列表
目标:把
丑陋,缓慢的方式:
1 | int("".join(map(str, [1,2,3,4,5,6,7,8]))) |
漂亮的
1 | reduce(lambda a,d: 10*a+d, [1,2,3,4,5,6,7,8], 0) |
1 2 3 4 5 6 | #!/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) |
例子:
1 2 3 4 | >>> lcm(100, 23, 98) 112700 >>> lcm(*range(1, 20)) 232792560 |
1 2 3 | >>> import __main__ >>> reduce(getattr,"os.path.abspath".split('.'), __main__) <function abspath at 0x009AB530> |
找到n个给定列表的交集:
1 2 3 | 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)) |
返回:
1 | result = set([3, 4, 5]) |
via:python-两个列表的交集
我认为减少是一个愚蠢的命令。因此:
1 | reduce(lambda hold,next:hold+chr(((ord(next.upper())-65)+13)%26+65),'znlorabggbbhfrshy','') |
我在代码中发现的
这正是(一些)像
当然,如果经常使用某些实例化(如
正如其他人提到的,可读性确实是一个问题。然而,你可以争辩说,人们之所以不太清楚是因为它不是许多人知道和/或使用的功能。
您可以用以下内容替换
1 | value = reduce(dict.__getitem__, 'abcde', json_obj) |
如果您已经将路径
功能组合:如果您已经有了要连续应用的功能列表,例如:
1 2 3 4 | 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] |
然后您可以连续地应用它们:
1 2 3 4 | >>> 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' |
在这种情况下,方法链接可能更易读。但有时这是不可能的,而且这种组合可能比
@Blair Conrad:你也可以使用sum实现glob/reduce,比如:
1 | files = sum([glob.glob(f) for f in args], []) |
这比您的两个示例中的任何一个都不冗长,完全是Python式的,而且仍然只是一行代码。
因此,为了回答最初的问题,我个人尽量避免使用reduce,因为它从来就不是真正必要的,而且我发现它比其他方法更不清楚。然而,有些人习惯于减少和倾向于列出理解(特别是Haskell程序员)。但是,如果您还没有考虑减少方面的问题,您可能不需要担心使用它。
1 | reduce(getattr, ('request', 'user', 'email'), self) |
当然,这相当于
1 | self.request.user.email |
但当您的代码需要接受任意的属性列表时,它是有用的。
(处理django模型时,任意长度的链接属性很常见。)
在对代码进行grepping之后,似乎我使用reduce的唯一目的就是计算阶乘:
1 | reduce(operator.mul, xrange(1, x+1) or (1,)) |
当需要找到一系列类
1 2 3 4 | >>> reduce(operator.or_, ({1}, {1, 2}, {1, 3})) # union {1, 2, 3} >>> reduce(operator.and_, ({1}, {1, 2}, {1, 3})) # intersection {1} |
(除了实际的
另一方面,如果你在处理
1 2 | >>> any((True, False, True)) True |
reduce不仅限于标量操作,还可以用于将事物分类为bucket。(这是我最常使用的reduce)。
想象一下这样一种情况,在这种情况下,您有一个对象列表,并且您希望基于对象中扁平存储的属性,以分层方式重新组织它。在下面的示例中,我使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | from lxml import etree from Reader import Reader class IssueReader(Reader): def articles(self): arts = self.q('//div3') # inherited ... runs an xpath query against the issue subsection = etree.XPath('./ancestor::div2/@type') section = etree.XPath('./ancestor::div1/@type') header_text = etree.XPath('./head//text()') return map(lambda art: { 'text_id': self.id, 'path': self.getpath(art)[0], 'subsection': (subsection(art)[0] or '[none]'), 'section': (section(art)[0] or '[none]'), 'headline': (''.join(header_text(art)) or '[none]') }, arts) def by_section(self): arts = self.articles() def extract(acc, art): # acc for accumulator section = acc.get(art['section'], False) if section: subsection = acc.get(art['subsection'], False) if subsection: subsection.append(art) else: section[art['subsection']] = [art] else: acc[art['section']] = {art['subsection']: [art]} return acc return reduce(extract, arts, {}) |
我在这里给出了这两个函数,因为我认为它显示了在处理对象时map和reduce如何能够很好地互补。同样的事情也可以通过for循环完成,…但是花一些时间在功能性语言上往往会让我从映射和减少的角度思考。
顺便说一下,如果有人能像我在
我正在为一种语言编写一个撰写函数,因此我使用reduce和apply操作符构造撰写函数。
简言之,compose将一个函数列表组合成一个函数。如果我有一个分阶段应用的复杂操作,我希望将其全部组合起来,如下所示:
1 | complexop = compose(stage4, stage3, stage2, stage1) |
这样,我就可以将它应用到如下表达式:
1 | complexop(expression) |
我希望它等同于:
1 | stage4(stage3(stage2(stage1(expression)))) |
现在,为了构建我的内部对象,我想说:
1 | Lambda([Symbol('x')], Apply(stage4, Apply(stage3, Apply(stage2, Apply(stage1, Symbol('x')))))) |
(lambda类生成用户定义的函数,而apply则生成函数应用程序。)
现在,减少,不幸的是,折叠错误的方式,所以我结束使用,大致:
1 | reduce(lambda x,y: Apply(y, x), reversed(args + [Symbol('x')])) |
要想知道什么是减产,请在repl中尝试这些方法:
1 2 | reduce(lambda x, y: (x, y), range(1, 11)) reduce(lambda x, y: (y, x), reversed(range(1, 11))) |
不确定这是否是你想要的,但是你可以在谷歌上搜索源代码。
按照链接搜索google代码搜索上的"function:reduce()lang:python"
乍一看,以下项目使用
- 莫宁
- 应用服务器
- 数字的
- 科学Python
等等,但这些并不令人惊讶,因为它们是巨大的项目。
reduce的功能可以使用函数递归来完成,我猜guido认为这更显式。
更新:
由于谷歌的代码搜索在2012年1月15日停止,除了恢复常规的谷歌搜索,还有一个叫做代码片段集合的东西看起来很有前途。在回答这个(封闭式)问题时提到了许多其他资源来替代谷歌代码搜索?.
更新2(2017年5月29日):
对于Python示例(在开源代码中)来说,一个好的来源是nullege搜索引擎。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | import os files = [ # full filenames "var/log/apache/errors.log", "home/kane/images/avatars/crusader.png", "home/jane/documents/diary.txt", "home/kane/images/selfie.jpg", "var/log/abc.txt", "home/kane/.vimrc", "home/kane/images/avatars/paladin.png", ] # unfolding of plain filiname list to file-tree fs_tree = ({}, # dict of folders []) # list of files for full_name in files: path, fn = os.path.split(full_name) reduce( # this fucction walks deep into path # and creates placeholders for subfolders lambda d, k: d[0].setdefault(k, # walk deep ({}, [])), # or create subfolder storage path.split(os.path.sep), fs_tree )[1].append(fn) print fs_tree #({'home': ( # {'jane': ( # {'documents': ( # {}, # ['diary.txt'] # )}, # [] # ), # 'kane': ( # {'images': ( # {'avatars': ( # {}, # ['crusader.png', # 'paladin.png'] # )}, # ['selfie.jpg'] # )}, # ['.vimrc'] # )}, # [] # ), # 'var': ( # {'log': ( # {'apache': ( # {}, # ['errors.log'] # )}, # ['abc.txt'] # )}, # []) #}, #[]) |
我使用
1 2 3 4 | vectors = (self.column_vector(getattr(self.table.c, column_name)) for column_name in self.indexed_columns) concatenated = reduce(lambda x, y: x.op('||')(y), vectors) compiled = concatenated.compile(self.conn) |
1 2 3 | def dump(fname,iterable): with open(fname,'w') as f: reduce(lambda x, y: f.write(unicode(y,'utf-8')), iterable) |
reduce可用于获取具有最大nth元素的列表
1 | reduce(lambda x,y: x if x[2] > y[2] else y,[[1,2,3,4],[5,2,5,7],[1,6,0,2]]) |
将返回[5,2,5,7],因为它是具有max 3rd元素的列表+
假设有一些年度统计数据存储了一个计数器列表。我们想找出不同年份每个月的最小/最大值。例如,一月份为10。2月份是15天。我们需要把结果存储在一个新的计数器中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | from collections import Counter stat2011 = Counter({"January": 12,"February": 20,"March": 50,"April": 70,"May": 15, "June": 35,"July": 30,"August": 15,"September": 20,"October": 60, "November": 13,"December": 50}) stat2012 = Counter({"January": 36,"February": 15,"March": 50,"April": 10,"May": 90, "June": 25,"July": 35,"August": 15,"September": 20,"October": 30, "November": 10,"December": 25}) stat2013 = Counter({"January": 10,"February": 60,"March": 90,"April": 10,"May": 80, "June": 50,"July": 30,"August": 15,"September": 20,"October": 75, "November": 60,"December": 15}) stat_list = [stat2011, stat2012, stat2013] print reduce(lambda x, y: x & y, stat_list) # MIN print reduce(lambda x, y: x | y, stat_list) # MAX |
我刚刚发现了
1 2 3 4 5 6 | reduce(lambda acc, elem: acc[:-1] + [acc[-1] + elem] if elem ==" " else acc + [elem], re.split("( )","a b c "), []) |
结果如下:
1 2 3 4 | ['a ', 'b ', 'c ', ''] |
请注意,它处理的边缘情况中流行的答案,所以没有。为了更深入的解释,我是重定向到原来的博客文章。
我有一个旧的pipegrep的python实现,它使用reduce和glob模块构建要处理的文件列表:
1 2 | files = [] files.extend(reduce(lambda x, y: x + y, map(glob.glob, args))) |
当时我觉得它很方便,但实际上没有必要,因为类似的东西也很好,而且可能更易读。
1 2 3 | files = [] for f in args: files.extend(glob.glob(f)) |
我有代表某种重叠间隔(基因组外显子)的对象,并使用
1 2 3 4 5 6 7 | class Exon: def __init__(self): ... def __and__(self,other): ... length = self.length + other.length # (e.g.) return self.__class__(...length,...) |
然后当我收集到它们(例如,在同一个基因中)时,我使用
1 | intersection = reduce(lambda x,y: x&y, exons) |
使用reduce()查找日期列表是否连续:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | from datetime import date, timedelta def checked(d1, d2): """ We assume the date list is sorted. If d2 & d1 are different by 1, everything up to d2 is consecutive, so d2 can advance to the next reduction. If d2 & d1 are not different by 1, returning d1 - 1 for the next reduction will guarantee the result produced by reduce() to be something other than the last date in the sorted date list. Definition 1: 1/1/14, 1/2/14, 1/2/14, 1/3/14 is consider consecutive Definition 2: 1/1/14, 1/2/14, 1/2/14, 1/3/14 is consider not consecutive """ #if (d2 - d1).days == 1 or (d2 - d1).days == 0: # for Definition 1 if (d2 - d1).days == 1: # for Definition 2 return d2 else: return d1 + timedelta(days=-1) # datelist = [date(2014, 1, 1), date(2014, 1, 3), # date(2013, 12, 31), date(2013, 12, 30)] # datelist = [date(2014, 2, 19), date(2014, 2, 19), date(2014, 2, 20), # date(2014, 2, 21), date(2014, 2, 22)] datelist = [date(2014, 2, 19), date(2014, 2, 21), date(2014, 2, 22), date(2014, 2, 20)] datelist.sort() if datelist[-1] == reduce(checked, datelist): print"dates are consecutive" else: print"dates are not consecutive" |