one line factorial in python
March 8th, 2007 by Lawrence David
here’s a compact way of calculating factorials in python. in fact, since this method doesn’t rely on for or while loops and their ancillary overhead, it might be one of the faster ways of calculating a factorial.
let’s say you’d like to calculate k!
>>> reduce(lambda i,j : i*j, range(1,k+1))
think you got a typo in the formula:
the i in the range function should be one?
reduce(lambda i,j : i*j, range(1,k+1))
thanks rickard – you were right about the typo!
Very nice! Just be aware that this doesn’t work for k=0.
Very nice and elegant!!!
Very cool one liner Lawrence. I just wanted to note that it can be easily made to work for the k=0 case by the following modification:
reduce(lambda i,j: i*j, range(1,k+1),1)
You don’t need to lambda-define multiplication. How about reduce(int.__mul__, range(1, k+1))?
Rich ! ….. you are cool ! …. no lambda ….. keep it as python is to be done …. int._mul_ ….
The correct function is ….
>>>reduce(int.__mul__, range(1, k+1),1)
Yeah, that helped. Thanks!
By changing range(…) with xrange(…), ie:
>>> reduce(int.__mul__, xrange(1, k+1), 1)
someone can accomplish even (slightly) better performance code as far as looping and memory efficiency is concerned (see help(xrange) for details).
Another “fix” would be to use the mul function from the operator module (import operator) so as not to have problems with the factorial of “big numbers”:
>>>import operator
>>> reduce(operator.mul, xrange(1, k+1))
Here are some measures trying to compute 60! using timeit module:
In [74]: timeit.Timer(‘reduce(lambda i,j: i*j, range(1, 61))’).timeit(number=100000)
Out[74]: 2.4469389915466309
In [75]: timeit.Timer(‘reduce(lambda i,j: i*j, xrange(1, 61))’).timeit(number=100000)
Out[75]: 2.3416600227355957
In [76]: timeit.Timer(‘import operator; reduce(operator.mul, xrange(1, 61))’).timeit(number=100000)
Out[76]: 1.5750751495361328
Why spend time on multiplying with one?
So I would use:
reduce(int.__mul__, xrange(2, k+1), 1)
I actually are using:
from operator import mul
fact = lambda k: reduce( mul, range( 2, k + 1 ), 1 )
fact( 61 )
Can anybody change the line “I actually are using:” into “I am actually using:” in my previous entry and remove this entry?