Simple question: How many trailing zero does 10000! have?
Simple to solve it using python
import math factorial_answer = str(math.factorial(10000)) print(len(factorial_answer) - len(factorial_answer.rstrip('0')))
Python think about 100ms and tell me the answer is 2499.
This question is name as “Trailing zeros”
https://en.wikipedia.org/wiki/Trailing_zeros
The question become:
So we can just integer divide 10000 by 5 and get 2000, integer divide 2000 by 5 and get 400…. and sum all answers (2000, 400, …) until get 0.
let’s using recursion
def f(r, c=0): if r == 0: return c else: return f(r // 5, c + r // 5) print(f(10000))
The function take two arguments, one for current answer, another for count result.
and make it into one line
f = lambda r, c=0: c if r == 0 else f(r // 5, c + r // 5) print(f(10000))
Here we assign lambda expression to f and invoke it recursively. However, assign lambda expression is not recommended in PEP8. 不, 这不PEP8. And function f is exposed in namespace. There are ways to make recursive into anonymous lambda function that won’t pollute namespace, as well as make it into really one line.
print((lambda a: lambda r, c = 0: a(a, r, c))(lambda s, r, c: c if r == 0 else s(s, r // 5, c + r // 5))(10000))
Another flaw is, we use same division twice, more precisely, “r // 5” twice.
To eliminate duplicate, closure may help.
def f(r): def _f(r): while r != 0: r //= 5 yield r return sum(_f(r)) print(f(10000))
The process become, constantly dividing number by 5 and yield it to sum, until zero.
Make a function for that “continuously do something and yield it, until some condition” operation
def repeat_w_func(initial_input, repeat_func=None, yield_input=False, end_func=None): """ constantly do calculate function and take output as next time input :param initial_input: the initial input :param repeat_func: the function that will be evaluate repeatedly if not set, the function behavior like itertools.repeat(initial_input) :param yield_input: if set to True, initial_input will be yield once before yielding repeat_func output :param end_func: the function that will end the loop and stop yielding. if not set, yielding will be endless :return: a generator """ result = initial_input if yield_input: yield result if repeat_func: while True: if end_func: if end_func(result): break result = repeat_func(result) yield result else: while True: yield initial_input
With brand new repeat with function function, we can solve the question elegantly, with help of itertools.takewhile function.
from itertools import takewhile print(sum(takewhile(lambda x: x != 0, repeat_w_func(10000, lambda x: x // 5))))
Future research
Solve in function programming language like Haskell.
Is there a written functional just work like the repeat_w_func function in python or package?