我想构建一个高效的Python迭代器/生成器,产生:
我称之为“composites_with_factors()”
假设我们已经一个小于N的素数列表,或者一个可以做同样的素数生成器。
请注意我:
我认为这可以通过一个聪明的递归生成器完成......
因此,例如,对composites_with_factors(16)的调用可能会产生:
# yields values in form of "composite_value, (factor_tuple)"
2, (2)
4, (2, 2)
8, (2, 2, 2)
6, (2, 3)
12, (2, 2, 3)
10, (2, 5)
14, (2, 7)
3, (3)
9, (3, 3)
15, (3, 5)
5, (5)
7, (7)
11, (11)
13, (13)
从输出的顺序可以看出,我设想通过从可用素数生成器上的最小素数开始,并输出小于N的素数的所有幂,然后再次尝试通过素数,但在每个阶段,看看我是否可以申请额外素数的权力(仍然小于N)。当完成与THAT素数的所有组合时,将其丢弃,并使用素数生成器上可用的下一个最低素数重复。
我尝试用“递归生成器”做这件事让我很惊讶什么时候用“yield”,“提升StopIteration”或“return”弹出递归,或者只是从递归函数中掉出来
感谢您的智慧!
附加说明:
我做现在有一种方法可以做到这一点:我已经编写了一个函数来计算因子数,所以我可以将它们分解为素数,并产生结果。没问题。我依靠“N号最低素数因子”的缓存来保持这种速度极快......对于N达到1000万。
然而,一旦我离开缓存,我们就会变成“天真”的因素。 (呸。)
这篇文章的重点是:
答案 0 :(得分:10)
假设primesiter(n)
在n
之前的所有素数上创建一个迭代器(primesiter
中不应包含1,或者在代码后输入inf.loop)
def composite_value(n, min_p = 0):
for p in primesiter(n):
# avoid double solutions such as (6, [2,3]), and (6, [3,2])
if p < min_p: continue
yield (p, [p])
for t, r in composite_value(n//p, min_p = p): # uses integer division
yield (t*p, [p] + r)
输出
>> list(composite_value(16))
[(2, [2]),
(4, [2, 2]),
(8, [2, 2, 2]),
(16, [2, 2, 2, 2]),
(12, [2, 2, 3]),
(6, [2, 3]),
(10, [2, 5]),
(14, [2, 7]),
(3, [3]),
(9, [3, 3]),
(15, [3, 5]),
(5, [5]),
(7, [7]),
(11, [11]),
(13, [13])]
注意:它也包括n(= 16),我使用list而不是元组。如果需要,两者都可以轻松解决,但我会将其作为练习。
答案 1 :(得分:4)
这是一个基于筛选的实现(请原谅非pythonic代码:)):
def sieve(n):
# start each number off with an empty list of factors
# note that nums[n] will give the factors of n
nums = [[] for x in range(n)]
# start the counter at the first prime
prime = 2
while prime < n:
power = prime
while power < n:
multiple = power
while multiple < n:
nums[multiple].append(prime)
multiple += power
power *= prime
# find the next prime
# the next number with no factors
k = prime + 1
if k >= n: # no primes left!!!
return nums
# the prime will have an empty list of factors
while len(nums[k]) > 0:
k += 1
if k >= n: # no primes left!!!
return nums
prime = k
return nums
def runTests():
primes = sieve(100)
if primes[3] == [3]:
print "passed"
else:
print "failed"
if primes[10] == [2,5]:
print "passed"
else:
print "failed"
if primes[32] == [2,2,2,2,2]:
print "passed"
else:
print "failed"
试验:
>>> runTests()
passed
passed
passed
在我的机器上,这需要56秒才能运行:
primes = sieve(14000000) # 14 million!
示例:
>>> primes[:10]
[[], [], [2], [3], [2, 2], [5], [2, 3], [7], [2, 2, 2], [3, 3]]
>>> primes[10000]
[2, 2, 2, 2, 5, 5, 5, 5]
>>> primes[65536]
[2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]
>>> primes[6561]
[3, 3, 3, 3, 3, 3, 3, 3]
>>> primes[233223]
[3, 17, 17, 269]
内存消耗:大约有5000万个整数,在1400万个列表中:
>>> sum(map(len, primes))
53303934
答案 2 :(得分:0)
递归(伪代码):
def get_factorizations_of_all_numbers( start = starting_point
, end = end_point
, minp = mimimum_prime
):
if start > end:
return Empty_List
if minp ^ 2 > end:
return list_of_all_primes( start, end )
else
a = minp * get_factorizations_of_all_numbers( rounddown(start/minp)
, roundup(end/minp)
)
b = get_factorizations_of_all_numbers( start
, end
, next_prime( minp )
)
return append( a , b )
get_factorizations_of_all_numbers( 1, n, 2 )