views:

3693

answers:

11

Do anyone here have any useful code which uses reduce() function of python? Is there any code other than the usual + and * that we see in the examples?

Refer Fate of reduce() in Python 3000 by GvR

+1  A: 

Not sure if this is what you are after but you can search source code on Google.

Follow the link for a search on 'function:reduce() lang:python' on Google Code search

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.

Brendan
"The functionality of reduce can be done using function recursion" ...Or a `for` loop.
Jason Orendorff
Also, searching for reduce() yields projects that define reduce functions within their code. You should search for lang:python "reduce(" to to find actual usages of the built-in function.
Seun Osewa
+1  A: 

I have an old Python implementation of pipegrep that uses reduce and the glob module to build a list of files to process:

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

I found it handy at the time, but it's really not necessary, as something similar is just as good, and probably more readable

files = []
for f in args:
    files.extend(glob.glob(f))
Blair Conrad
How about a list comprehension? This seems like a perfect application for it:`files = [glob.glob(f) for f in args]`
steveha
Actually, @steveha, your example will result in a list of lists of expanded globs, rather than a flat list of all items that match the globs, but you could use a list comprehension + sum, as @[Eli Courtwright](#16198) points out.
Blair Conrad
Okay, you are correct, sorry about that. I still don't like the combination of extend/reduce/lambda/map very much! I would recommend importing `itertools`, using the `flatten()` recipe from http://docs.python.org/library/itertools.html, and then writing: `files = flatten(glob.glob(f) for f in args)` (And this time, I tested the code before posting it, and I know this works correctly.)
steveha
+6  A: 

@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.

Eli Courtwright
A: 

@Eli: thanks! I overlooked sum, probably mostly because I wrote my pipegrep off 1.5.2, and I'm not particularly good at checking out new language features (I'm lazy and copy my old code - I know, I'm hardly the only one). I can't wait to go and try out my new idiom!

Blair Conrad
+2  A: 

After grepping my code, it seems the only thing I've used reduce for is calculating the factorial:

reduce(operator.mul, xrange(1, x+1) or (1,))
Tomi Kyöstilä
+2  A: 

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.

mweerden
+7  A: 

The other uses I've found for it besides + and * were with and and or, but now we have any and all to replace those cases.

foldl and foldr do come up in Scheme a lot...

Here's some cute usages:

Flatten a list

Goal: turn [[1, 2, 3], [4, 5], [6, 7, 8]] into [1, 2, 3, 4, 5, 6, 7, 8].

reduce(list.__add__, [[1, 2, 3], [4, 5], [6, 7, 8]], [])

List of digits to a number

Goal: turn [1, 2, 3, 4, 5, 6, 7, 8] into 12345678.

Ugly, slow way:

int("".join(map(str, [1,2,3,4,5,6,7,8])))

Pretty reduce way:

reduce(lambda a,d: 10*a+d, [1,2,3,4,5,6,7,8], 0)
Claudiu
Why did you append the ", 0" in the last example? To be able to handle the eventuality of an empty list, or are there other reasons?
conny
For flattening a list, I prefer list(itertools.chain(*nested_list))
Roberto Bonvallet
@conny: i think you always need an initial element. in this case, ti's 0. otherwise, what would 'd' be when looking at the first element?
Claudiu
when no initial value is given, reduce just applies the reduction to the first *two* elements. if no initial value is given and there is only one element, then no reduction occurs.... I think...
TokenMacGuy
@Roberto: That doesn't handle nested lists.
Daenyth
@Daenyth: The ``reduce`` solution doesn't either!
Roberto Bonvallet
sum([[1, 2, 3], [4, 5], [6, 7, 8]], [])
tolomea
+5  A: 

reduce() can be used to find Least common multiple for 3 or more numbers:

def lcmm(*args):
    return reduce(lcm, args)

>>> lcmm(100, 23, 98)
112700
>>> lcmm(*range(1, 20))
232792560
J.F. Sebastian
+2  A: 

reduce() could be used to resolve dotted names (where eval() is too unsafe to use):

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

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:

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

This way, I can then apply it to an expression like so:

complexop(expression)

And I want it to be equivalent to:

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

Now, to build my internal objects, I want it to say:

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

(The Lambda class builds a user-defined function, and Apply builds a function application.)

Now, reduce, unfortunately, folds the wrong way, so I wound up using, roughly:

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

To figure out what reduce produces, try these in the REPL:

reduce(lambda x, y: (x, y), range(1, 11))
reduce(lambda x, y: (y, x), reversed(range(1, 11)))
ben
+1  A: 

Find intersection of N given list:

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

returns:

result = set([3, 4, 5])

via: Python - Intersection of two lists

ssoler