Welcome, guest | Sign In | My Account | Store | Cart

reduce is a pretty nice built-in, but its usage in everyday code is seemingly rare. If you've been looking for excuses to use reduce, here are a few useful recipes to get you started.

Python, 42 lines
 ``` 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``` ```import operator def factorial(n): """Calculate n factorial""" return reduce(operator.mul, range(2, n+1), 1) def intersection(*sets): """Get the intersection of all input sets""" return reduce(set.intersection, sets) def union(*sets): """Get the union of all input sets""" return reduce(set.union, sets) def join(*seqs): """Join any input sequences that support concatenation""" return reduce(operator.concat, seqs) """ Some usage: >>> factorial(3) 6 >>> factorial(10) 3628800 >>> a = set([1, 2, 3, 4, 5]) >>> b = set([5, 6, 3, 7]) >>> c = set([8, 7, 5]) >>> intersection(a, b, c) set([5]) >>> union(a, b, c) set([1, 2, 3, 4, 5, 6, 7, 8]) >>> join("one", "two", "three", "four") 'onetwothreefour' >>> join([1, 2, 3], [5, 6], [6, 7]) [1, 2, 3, 4, 5, 6, 7] """ ```

If you post a clever way to use reduce to solve a common problem, post it here and I'll add it to the recipe.

Brandon Beck 17 years, 2 months ago

Chained replacements in a string. One way that I've recently found to use reduce is for the chained replacement of characters in a string.

``````def replace(text, replacements):
for (old, new) in replacements:
text = text.replace(old, new)

return text
``````

I use:

``````def replace(text, replacements):
return reduce(lambda s, (old, new): s.replace(old, new), replacements, text)
``````

And an example:

``````replace("This is a normal string", [(c, c.upper()) for c in "aeiou"])
'ThIs Is A nOrmAl strIng'
``````

Ironically enough, on my machine the the reduce version is about 37% slower than the looped version on the example I gave above.

Frank P Mora 17 years, 1 month ago

Anonymous in-line list comprehension functions. Python is a wonderfully expressive programming language. Some expressions such as those involving reduce, are more elegant and simple than others. I enjoy and value the functional facilities and functions as first class objects in Python. I have, however, seen evidence that some of these are in jeopardy (google for The fate of reduce() in Python.)

Here are in-line list comprehension versions of your functions and a bit more. The general form is: set initial value, set iteration values and successively apply an infix or prefix function cumulatively and finally take the last value of the generated list.

``````>>> T=[set(s) for s in [(1,2,3,4,5),(2,3,4,5,6),(3,4,5,6,7),(4,5,6,7,8)]]

>>> f=set.intersection
>>> [ s for s in [f(*T[:2])] for i in range(2,len(T)) for s in [f(s,T[i])] ][-1]
set([4, 5])     ## issues the null set if no intersection between all given sets

>>> f=set.union
>>> [ s for s in [f(*T[:2])] for i in range(2,len(T)) for s in [f(s,T[i])] ][-1]
set([1, 2, 3, 4, 5, 6, 7, 8])

>>> # join
>>> T=[(1,2,3,4,5,6,7),(3,4,5,6,7),(5,6,7),(7,8,9,2,1,5)]

>>> [ s for s in [T[0]] for i in range(1,len(T)) for s in [s + T[i]] ][-1]
(1, 2, 3, 4, 5, 6, 7, 3, 4, 5, 6, 7, 5, 6, 7, 7, 8, 9, 2, 1, 5)

>>> t=["abcd","efgh","ijkl","mnop","qrst"]

>>> [ s for s in [T[0]] for i in range(1,len(T)) for s in [s + T[i]] ][-1]
'abcdefghijklmnopqrst'

>>> # factorial
>>> fac = 6
>>> [j for j in [1] for i in range(2, fac+1) for j in [j*i]][-1]
720

>>> nl = [2, 3, 6, 18]

>>> # sum
>>> [j for j in [0] for i in nl for j in [j + i]][-1]
29
>>> # product
>>> [j for j in [1] for i in nl for j in [j * i]][-1]
648
>>>

Much thanks to Steven Bethard for the cleaner form of this pattern.
``````
Frank P Mora 17 years, 1 month ago

And for predicates.

``````>>> l=(20,30,40,50,60,70,80,90,1,2,3,4,5)

>>> # all function
>>> [ p for p in [l[0]>42] for i in range(1,len(l)) for p in [p and l[i]>42] ][-1]
False

>>> # any function
>>> [ p for p in [l[0]>42] for i in range(1,len(l)) for p in [p  or l[i]>42] ][-1]
True

The pattern *is* very general and regular
``````
Paul McGuire 16 years, 1 month ago

Use reduce to call divmod with succesive divisors. I used reduce to build up a tuple of the parts of an elapsed time, starting with a floating point number of seconds. Posted at recipe: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/511486

-- Paul

 Created by Brian Beck on Fri, 31 Mar 2006 (PSF)