这不是埃拉托色尼的筛子,尽管它看起来是。事实上,情况要糟糕得多。Sieve 是寻找素数的最佳算法。
见http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
编辑:我已将https://stackoverflow.com/a/9302299/711085修改为单线(最初它不是真正的筛子,但现在......可能......):
reduce( (lambda r,x: r-set(range(x**2,N,x)) if (x in r) else r),
range(2,N), set(range(2,N)))
演示:
>>> primesUpTo(N): lambda N: reduce(...)
>>> primesUpTo(30)
{2, 3, 5, 7, 11, 13, 17, 19}
可悲的是,我认为虽然这在函数式编程语言中会很有效,但由于非持久(共享状态和不可变)数据结构,它在 python 中可能效率不高,并且 python 中的任何筛子都需要使用突变来实现可比性能。如果我们非常想的话,我们仍然可以把它塞进一个单列中。但首先...
普通筛:
>>> N = 100
>>> table = list(range(N))
>>> for i in range(2,int(N**0.5)+1):
... if table[i]:
... for mult in range(i**2,N,i):
... table[mult] = False
...
>>> primes = [p for p in table if p][1:]
>>> primes
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
我们现在可以在同一行定义和调用匿名函数,以及[...].__setitem__
进行内联突变的技巧,以及返回... and foo
时评估的技巧:...
foo
>>> primesUpTo = lambda N: (lambda table: [[table.__setitem__(mult,False) for mult in range(i**2,N,i)] for i in range(2,int(N**0.5)+1) if table[i]] and [p for p in table if p][1:])(list(range(N)))
>>> primesUpTo(30)
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
继续惊恐地畏缩,单行扩展(奇怪的漂亮,因为你几乎可以直接翻译控制流,但对一切都是可怕的滥用):
lambda N:
(lambda table:
[[table.__setitem__(mult,False) for mult in range(i**2,N,i)]
for i in range(2,int(N**0.5)+1) if table[i]]
and [p for p in table if p][1:]
)(list(range(N)))
在我的机器上,这个单线变异版本在 10 8左右放弃了,而原始变异版本在 10 9左右放弃了,内存不足(奇怪)。
原版在 10 7reduce
放弃。所以也许它毕竟不是那么低效(至少对于您可以在计算机上处理的数字)。
编辑2似乎您可以更简洁地滥用副作用:
reduce( (lambda r,x: (r.difference_update(range(x**2,N,x)) or r)
if (x in r) else r),
range(2,N), set(range(2,N)))
它在 10 8左右放弃,与单线变异版本相同。
编辑3:这以O(N)经验复杂度运行,而没有difference_update
它以O(n^2.2) 复杂度运行。
将减少的范围限制为上限的 sqrt,并仅使用赔率,两者都会导致额外的加速(相应地2倍和1.6 倍):
reduce( (lambda r,x: (r.difference_update(range(x*x,N,2*x)) or r)
if (x in r) else r),
range(3, int((N+1)**0.5+1), 2),
set([2] + range(3,N,2)))