Eratosthenes筛网中的发生器递归跳过步骤

时间:2018-12-16 22:55:23

标签: python recursion generator sieve-of-eratosthenes generator-expression

我在这里编写的筛网算法遇到了问题。我已经尝试修复了大约10个小时。我到处都是类似的问题,但似乎找不到任何遇到此问题的人。我是python的新手,在阅读了很多生成器文档之后,我设法编写了有效的代码。但是,我仍然不知道为什么我的第一次尝试失败了。

我想出的是,似乎在每个后续的筛分步骤中实际上并未清空gen1。因此,我尝试在名称gen1和gen2之间交替使用,删除每个名称以避免此问题。那也不起作用。

我真的很感谢对此的一些见解,以及对改善我现在所拥有的一切建议。

这是失败的代码:

def primes(n):
    "yields primes up to n. For use with large n"
    q = 0
    yield 2
    gen1 = (x for x in range(3,n,2))
    while q*q < n:
        q = next(gen1)
        gen1 = (x for x in gen1 if x%q != 0)
        yield q
    else:
        while 1:
            try:
                yield next(gen1)
            except:
                StopIteration
                break

这是我当前的代码:

import math
global gen1
global gen
def gen1(x):
    for i in range(3,x,2):
        yield i
def gen(generator,n):
    "Input generator and current starting 'index' for the generator"
    # Recursively defines new generator for sieve of Eratosthenes
    for i in range(n+1):
        predicate = next(generator)
        yield predicate
    for i in generator:
        if i % predicate != 0:
            yield i
def primes(n):
    yield 2
    a = gen1(n)
    for i in range(math.ceil(math.sqrt(n))):
        a = gen(a,i)
    yield from a

1 个答案:

答案 0 :(得分:4)

基本问题是范围之一。在这一行:

  gen1 = (x for x in gen1 if x%q != 0)

使用的q的值不是 生成器表达式创建时绑定的值q ,而是生成器表达式正在执行时,q的值(不断变化!)。这与在任何类型的嵌套函数中引用非局部变量的方式相同。

要在创建时捕获绑定,一种显而易见的简便方法是改为编写一个函数,然后传递要使用的值。例如,在这方面和其他几个方面,这种重写更像是Pythonic:

def primes(n):
    "yields primes up to n. For use with large n"

    def gen(gen1, q):
        for x in gen1:
            if x % q:
                yield x

    q = 0
    yield 2
    gen1 = iter(range(3, n, 2))
    while q*q < n:
        q = next(gen1)
        gen1 = gen(gen1, q)
        yield q
    yield from gen1

现在gen()主体中使用的值正好是传递给它的值,因此很明显,而不是神秘的;-)