使用reduce()的有用代码?

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

参考GvR 在 Python3000 中reduce()的命运

除了+和*之外,我发现的其他用途是和和和,但是现在我们有anyall来代替这些情况。

scheme很多…

这里有一些可爱的用法:

展开列表

目标:将[[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) 

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) 

例:

 >>> lcm(100, 23, 98) 112700 >>> lcm(*range(1, 20)) 232792560 

reduce()可用于parsing虚线名称(其中eval()太不安全)。

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

findN个给定列表的交集:

 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]) 

通过: Python – 两个列表的交集

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

这正是(一些)function程序员喜欢reduce (或fold函数,因为这样的函数通常被称为)的原因。 经常有许多二进制函数,如+*minmax ,串联,在我的情况下, make_andmake_or 。 有一个reduce使得提升这些操作到列表(或树或任何你得到的折叠函数一般)是微不足道的。

当然,如果经常使用某些实例(如sum ),那么你不想继续写reduce 。 但是,不要用一些for循环来定义sum ,你可以reduce 简单地定义它。

正如其他人所说的,可读性的确是一个问题。 然而,你可能会争辩说,人们认为reduce “清晰”的唯一原因是因为它不是许多人所了解和/或使用的function。

我认为减less是一个愚蠢的命令。 因此:

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

@Blair Conrad:你也可以实现你的glob / reduce使用总和,就像这样:

 files = sum([glob.glob(f) for f in args], []) 

这比你的两个例子中的任何一个都不那么冗长,完全是Pythonic,并且仍然只有一行代码。

所以要回答原来的问题,我个人尽量避免使用减less,因为它从来没有真正的必要,我觉得它不如其他方法清楚。 然而,有些人习惯于减less并且喜欢列出理解(特别是Haskell程序员)。 但是,如果你还没有考虑减less问题,你可能不需要担心使用它。

你可以用下面的代码replacevalue = json_obj['a']['b']['c']['d']['e']

 value = reduce(dict.__getitem__, 'abcde', json_obj) 

如果你已经有一个patha/b/c/..作为列表。 例如, 使用列表中的项目更改嵌套字典的字典中的值 。

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

 reduce(getattr, ('request', 'user', 'email'), self) 

当然,这相当于

 self.request.user.email 

但是当你的代码需要接受一个任意的属性列表时,这是非常有用的。

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

在我的代码之后,看起来我唯一使用的方法是计算阶乘:

 reduce(operator.mul, xrange(1, x+1) or (1,)) 

function组成 :如果您已经有一系列您想要连续申请的function,例如:

 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))))语法更具可读性和可维护性。

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

 >>> reduce(operator.or_, ({1}, {1, 2}, {1, 3})) # union {1, 2, 3} >>> reduce(operator.and_, ({1}, {1, 2}, {1, 3})) # intersection {1} 

(除了实际的set ,这些的例子是Django的Q对象 。)

另一方面,如果你正在处理bool ,你应该使用anyall

 >>> any((True, False, True)) True 

减less不限于标量操作; 它也可以用来把东西分成桶。 (这是我最常使用的减less)。

想象一下,你有一个对象列表的情况,你想重新组织分层次的基础上,对象存储在平坦的属性。 在以下示例中,我使用articles函数生成了与XML编码的报纸中的articles相关的元数据对象列表。 articles生成一个XML元素列表,然后通过它们逐一映射,生成对象,其中包含一些关于它们的有趣信息。 在前端,我打算让用户按部分/子部分/标题浏览文章。 因此,我使用reduce来获取文章列表并返回反映章节/子章节/文章层次结构的单个词典。

 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循环来实现,但是用function性语言花费一些认真的时间往往会使我思考地图和缩小。

顺便说一下,如果有人有更好的方式来设置属性,如我在extract ,你想设置的财产的父母可能不存在,请让我知道。

不知道这是否是你以后,但你可以search谷歌的源代码 。

在Google Codesearch上按照链接search“function:reduce()lang:python”

乍一看下面的项目使用reduce()

  • MoinMoin的
  • Zope的
  • 数字
  • ScientificPython

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

reduce的function可以通过函数recursion来完成,我猜Guido认为它更加明确。

更新:

由于谷歌的代码search在2012年1月15日停止,除了恢复到常规的谷歌search之外,还有一些称为代码片段收集的看起来很有前途的东西。 在回答这个(封闭)问题中提到了一些其他资源replaceGoogle代码search? 。

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

Nullegesearch引擎是Python示例的一个很好的来源(在开源代码中)。

我正在为一种语言编写一个组合函数,所以我使用reduce和我的apply运算符一起构造了组合函数。

简而言之,撰写需要一个function列表来组成一个单一的function。 如果我有一个分阶段应用的复杂操作,我想把它放在一起,就像这样:

 complexop = compose(stage4, stage3, stage2, stage1) 

这样,我可以将它应用于如下的expression式:

 complexop(expression) 

我希望它相当于:

 stage4(stage3(stage2(stage1(expression)))) 

现在,为了build立我的内部对象,我想让它说:

 Lambda([Symbol('x')], Apply(stage4, Apply(stage3, Apply(stage2, Apply(stage1, Symbol('x')))))) 

(Lambda类构build一个用户定义的函数,Apply构build一个函数应用程序。)

现在,不幸的是,减less,折叠错误的方式,所以我最终使用,大致:

 reduce(lambda x,y: Apply(y, x), reversed(args + [Symbol('x')])) 

要弄清楚产生什么样的reduce,可以在REPL中试试这些:

 reduce(lambda x, y: (x, y), range(1, 11)) reduce(lambda x, y: (y, x), reversed(range(1, 11))) 
 import os files = [ # full filenames "var/log/apache/errors.log", "home/kanehttp://img.dovov.comavatars/crusader.png", "home/jane/documents/diary.txt", "home/kanehttp://img.dovov.comselfie.jpg", "var/log/abc.txt", "home/kane/.vimrc", "home/kanehttp://img.dovov.comavatars/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'] # )}, # []) #}, #[]) 
 def dump(fname,iterable): with open(fname,'w') as f: reduce(lambda x, y: f.write(unicode(y,'utf-8')), iterable) 

我用reduce 来连接PostgreSQLsearch向量的列表 在sqlalchemy可search的运算符:

 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) 

我有一个使用reduce和glob模块来构build要处理的文件列表的pipegrep的旧Python实现:

 files = [] files.extend(reduce(lambda x, y: x + y, map(glob.glob, args))) 

当时我发现它很方便,但它并不是必须的,因为类似的东西同样好,可能更具可读性

 files = [] for f in args: files.extend(glob.glob(f)) 

reduce可以用来得到最大的第n个元素的列表

 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],因为它是最大的第三个元素+的列表

假设有一些年度统计数据存储在计数器列表中。 我们希望在不同年份的每月查找MIN / MAX值。 例如,1月份是10,而2月份是15。我们需要将结果存储在一个新的计数器中。

 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 

我有代表某种重叠区间(基因组外显子)的对象,并使用__and__重新定义它们的交集:

 class Exon: def __init__(self): ... def __and__(self,other): ... length = self.length + other.length # (eg) return self.__class__(...length,...) 

然后,当我收集他们(例如,在同一个基因),我使用

 intersection = reduce(lambda x,y: x&y, exons) 

我刚刚发现reduce有用用法: 拆分string而不删除分隔符 。 代码完全来自编程式的博客。 代码如下:

 reduce(lambda acc, elem: acc[:-1] + [acc[-1] + elem] if elem == "\n" else acc + [elem], re.split("(\n)", "a\nb\nc\n"), []) 

结果如下:

 ['a\n', 'b\n', 'c\n', ''] 

请注意,它处理在SO中stream行的答案没有的边缘情况。 为了更深入的解释,我将您redirect到原来的博客文章。

使用reduce()来确定date列表是否连续:

 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"