我已经实现了项目欧拉问题5的解决方案:
2520是最小的数,可以除以从1到10的每一个数,没有任何余数。什么是最小的正数,可以被从1到20的所有数字整除?
我的解决方案使用Python2.7,由我创建的一个模块组成,该模块查找数字的主要因素-- factorization
模块。它包含在同名Python源文件中实现的函数factors()
和primegen()
。在项目的顶层,我定义了一个函数smallest_multiple()
,它使用factors()
,并在同一个文件中定义一个main()
函数来驱动它。
factorization
模块primegen.py:
import itertools
def primegen(upper):
"""Return generator yielding all primes less than upper
>>> list(primegen(10))
[2, 3, 5, 7]
>>> list(primegen(30))
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
"""
# http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
marked = [False] * (upper - 2)
# using generator here lets us lazily evaluate whether
# a number has been marked
def next_p():
for i,v in enumerate(marked):
if not v:
yield i
def generate_primes():
for p_idx in next_p():
p = p_idx + 2
cursor = p
while True:
cursor = cursor + p
try:
marked[cursor-2] = True
except IndexError:
break
yield p
return generate_primes()
factors.py:
from factorization.primegen import primegen
def factors(n):
"""generator function yielding the prime factors of n
Heavily derived from http://en.wikipedia.org/wiki/Trial_division
>>> list(factors(14))
[2, 7]
>>> list(factors(13195))
[5, 7, 13, 29]
>>> list(factors(8))
[2, 2, 2]
"""
for p in primegen(int(n**0.5) + 1):
# sqrt(n) < p => n = q * (p^k), where k is 0 or 1, and q is product of each element of factors
if p*p > n:
break
# append factor for each time it appears
while not n%p:
yield p
n = n / p
if n > 1:
yield n
e5.py:
#!/usr/bin/env python
from factorization.factors import factors
def smallest_multiple(n):
"""Returns smallest multiple evenly divisble by each 1..n in N
>>> smallest_multiple(10)
2520
"""
# for each number <= n, find its prime factors p1^k1, p2^k2, ...
# store as prime => exponent
# replace existing stored exponents only if the replacement is greater
# for each prime=>exponent
# result = result * prime^exponent
factor_exp_map = {}
for i in xrange(n,0,-1):
facs = list(factors(i))
for factor in facs:
fact_count = facs.count(factor)
cur_fact_count = factor_exp_map.get(factor,0)
if (fact_count > cur_fact_count):
factor_exp_map[factor] = fact_count
result = 1
for factor, exponent in factor_exp_map.iteritems():
result = result * factor**exponent
return result
def main():
print('result = {0}'.format(smallest_multiple(20)))
if __name__ == '__main__':
main()
整个项目可以找到论吉乌布。它的唯一增加是一个崇高文本2项目和一些脚本,以便在编辑器中运行doctest。
我确实对这段代码有一些特别的关注。我发现smallest_multiple()
是奇怪的和笨重的-特别是迭代每个因素元素并要求它的计数。似乎应该有一些更优雅的方法来汇总这些因素及其指数。我想知道我的docstring和doctest是否合理,以及我的模块组织是否一致。我还想知道我是否在滥用生成器,特别是在doctest中,在每个生成器上调用list()
以获得结果,以及在primegen()
中调用嵌套生成器函数。
一般来说,我还想得到关于这个代码是怎样的Pythonic的反馈。我一直在努力记住PEP 8,但是我匆忙忽略的任何偏差都是很好的了解。在输入验证和健壮性方面,我也做得不多,所以我希望能就这样做的惯用方式提供一般性建议。
发布于 2013-11-19 18:41:33
这是相当不错的Python。我的意见是:
factors()
函数的责任。前一次审查说明了这些原则。
发布于 2013-11-20 21:32:16
我的眼睛里有几样东西:
factors
的调用都会从头开始运行Eratosthenes的筛子。for
循环相当笨重的替代(2*p-2,len(标记),p):标记游标= Truehttps://codereview.stackexchange.com/questions/35499
复制相似问题