这并不是埃拉托斯特尼筛法,尽管它看起来像是。实际上,它要糟糕得多。筛法是找素数的最佳算法。
参见 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__
的hack来进行内联变异,以及使用
... and foo
的hack来在返回
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 处放弃,由于内存不足(奇怪)。
原始的 reduce
版本在 107 时放弃。因此,它可能并不是那么低效(至少对于您可以处理的计算机数字来说)。
编辑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)))
它在大约108时放弃,与单行变异版本相同。
编辑3:这个运行时间为O(N)经验复杂度,而没有difference_update
的情况下,它运行在O(n^2.2)的复杂度。
限制减少范围,到上限的平方根,并且只处理奇数,都会导致额外的加速(分别为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)))
locals['_[1]']
来引用它。 - APerson