Does anyone here have any useful code which uses reduce() function in python? Is there any code other than the usual + and * that we see in the examples?
The usage of reduce that I found in my code involved the situation where I had some class structure for logic expression and I needed to convert a list of these expression objects to a conjunction of the expressions. I already had a function make_and to create a conjunction given two expressions, so I wrote reduce(make_and,l). (I knew the list wasn’t empty; otherwise it would have been something like reduce(make_and,l,make_true).)
This is exactly the reason that (some) functional programmers like reduce (or fold functions, as such functions are typically called). There are often already many binary functions like +, *, min, max, concatenation and, in my case, make_and and make_or. Having a reduce makes it trivial to lift these operations to lists (or trees or whatever you got, for fold functions in general).
Of course, if certain instantiations (such as sum) are often used, then you don’t want to keep writing reduce. However, instead of defining the sum with some for-loop, you can just as easily define it with reduce.
Readability, as mentioned by others, is indeed an issue. You could argue, however, that only reason why people find reduce less “clear” is because it is not a function that many people know and/or use.
回答 6
函数组成:如果您已经有了要连续应用的函数列表,例如:
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'
>>> 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'
In this case, method chaining may be more readable. But sometimes it isn’t possible, and this kind of composition may be more readable and maintainable than a f1(f2(f3(f4(x)))) kind of syntax.
回答 7
您可以替换value = json_obj['a']['b']['c']['d']['e']为:
value = reduce(dict.__getitem__,'abcde', json_obj)
@Blair Conrad: You could also implement your glob/reduce using sum, like so:
files = sum([glob.glob(f) for f in args], [])
This is less verbose than either of your two examples, is perfectly Pythonic, and is still only one line of code.
So to answer the original question, I personally try to avoid using reduce because it’s never really necessary and I find it to be less clear than other approaches. However, some people get used to reduce and come to prefer it to list comprehensions (especially Haskell programmers). But if you’re not already thinking about a problem in terms of reduce, you probably don’t need to worry about using it.
I’m writing a compose function for a language, so I construct the composed function using reduce along with my apply operator.
In a nutshell, compose takes a list of functions to compose into a single function. If I have a complex operation that is applied in stages, I want to put it all together like so:
Reduce isn’t limited to scalar operations; it can also be used to sort things into buckets. (This is what I use reduce for most often).
Imagine a case in which you have a list of objects, and you want to re-organize it hierarchically based on properties stored flatly in the object. In the following example, I produce a list of metadata objects related to articles in an XML-encoded newspaper with the articles function. articles generates a list of XML elements, and then maps through them one by one, producing objects that hold some interesting info about them. On the front end, I’m going to want to let the user browse the articles by section/subsection/headline. So I use reduce to take the list of articles and return a single dictionary that reflects the section/subsection/article hierarchy.
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, {})
I give both functions here because I think it shows how map and reduce can complement each other nicely when dealing with objects. The same thing could have been accomplished with a for loop, … but spending some serious time with a functional language has tended to make me think in terms of map and reduce.
By the way, if anybody has a better way to set properties like I’m doing in extract, where the parents of the property you want to set might not exist yet, please let me know.
At first glance the following projects use reduce()
MoinMoin
Zope
Numeric
ScientificPython
etc. etc. but then these are hardly surprising since they are huge projects.
The functionality of reduce can be done using function recursion which I guess Guido thought was more explicit.
Update:
Since Google’s Code Search was discontinued on 15-Jan-2012, besides reverting to regular Google searches, there’s something called Code Snippets Collection that looks promising. A number of other resources are mentioned in answers this (closed) question Replacement for Google Code Search?.
Update 2 (29-May-2017):
A good source for Python examples (in open-source code) is the Nullege search engine.
回答 16
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 filesfor full_name in files:
path, fn = os.path.split(full_name)
reduce(# this fucction walks deep into path# and creates placeholders for subfolderslambda 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']# )},# [])#},#[])
from collections importCounter
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)# MINprint reduce(lambda x, y: x | y, stat_list)# MAX
Let say that there are some yearly statistic data stored a list of Counters. We want to find the MIN/MAX values in each month across the different years. For example, for January it would be 10. And for February it would be 15. We need to store the results in a new Counter.
Note that it handles edge cases that popular answer in SO doesn’t. For more in-depth explanation, I am redirecting you to original blog post.
回答 23
使用reduce()来确定日期列表是否连续:
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 1if(d2 - d1).days ==1:# for Definition 2return 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"
Using reduce() to find out if a list of dates are consecutive:
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"