由于没有人试图用旧的好reduce
方法来破解它,我将接受这个职业。此方法对于此类问题不灵活,因为它对参数数组执行重复操作的循环,并且默认情况下无法中断此循环。在我们实现了自己的interupted reduce
for 中断循环之后,大门打开了,如下所示:
from functools import reduce
def inner_func(func, cond, x, y):
res = func(x, y)
if not cond(res):
raise StopIteration(x, y)
return res
def ireducewhile(func, cond, iterable):
# generates intermediary results of args while reducing
iterable = iter(iterable)
x = next(iterable)
yield x
for y in iterable:
try:
x = inner_func(func, cond, x, y)
except StopIteration:
break
yield x
之后,我们可以使用一些与标准 Python reduce 方法func
的输入相同的内容。让其以下列方式定义:func
def division(c):
num, start = c
for i in range(start, int(num**0.5)+1):
if num % i == 0:
return (num//i, i)
return None
假设我们要分解一个数字 600851475143,重复使用此函数后此函数的预期输出应为:
(600851475143, 2) -> (8462696833 -> 71), (10086647 -> 839), (6857, 1471) -> None
元组的第一项是一个数字,该division
方法从第二项开始尝试除以最小除数,并以该数字的平方根结束。如果不存在除数,则返回 None。现在我们需要从这样定义的迭代器开始:
def gener(prime):
# returns and infinite generator (600851475143, 2), 0, 0, 0...
yield (prime, 2)
while True:
yield 0
最后,循环的结果是:
result = list(ireducewhile(lambda x,y: div(x), lambda x: x is not None, iterable=gen(600851475143)))
#result: [(600851475143, 2), (8462696833, 71), (10086647, 839), (6857, 1471)]
输出素数除数可以通过以下方式捕获:
if len(result) == 1: output = result[0][0]
else: output = list(map(lambda x: x[1], result[1:]))+[result[-1][0]]
#output: [2, 71, 839, 1471]
笔记:
为了提高效率,您可能希望使用位于特定范围内的预生成素数,而不是该范围内的所有值。