列表推导是 Python 中一个强大的工具。将它们视为类固醇中的 for 循环。:-) 您可以使用它们来实现试除法,这是一种查找素数的简单方法。
它是这样工作的:
In [4]: sum(prime_list(100))
Out[4]: 1061
prime_list
功能:
def prime_list(num):
"""Returns a list of all prime numbers up to and including num.
Based on trial division.
:num: highest number to test
:returns: a list of primes up to num
"""
if num < 3:
raise ValueError('this function only accepts arguments > 2')
candidates = range(3, num+1, 2) # (a)
L = [c for c in candidates if all(c % p != 0 for p in range(3, c, 2))] #(b)
return [1, 2] + L
现在解释一下。除 2 外,所有素数都是奇数。所以从 3 到(在这种情况下为 100)的所有奇数num
都是素数的候选者。让我们生成一个在 (a) 处完成的列表:
In [5]: num = 100
In [6]: range(3, num+1, 2)
Out[6]: [3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95, 97, 99]
要使奇数c
成为质数,必须确保对c
所有先前奇数取模后p
必须为非零。假设c
是25。
In [7]: c = 25
然后p
在:
In [8]: range(3, c, 2)
Out[8]: [3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23]
现在检查c
模数p
:
In [9]: [c % p != 0 for p in range(3, c, 2)]
Out[9]: [True, False, True, True, True, True, True, True, True, True, True]
我们知道 25 % 5 == 0,所以列表中的第二项是False
. 但是,要使一个数成为素数,列表中的所有项目都必须为真:
In [10]: all(c % p != 0 for p in range(3, c, 2))
Out[10]: False
所以 25 不是素数。
让我们再试一次c
是 41:
In [11]: c = 41
In [12]: range(3, c, 2)
Out[12]: [3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39]
In [13]: [c % p != 0 for p in range(3, c, 2)]
Out[13]: [True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True]
In [14]: all(c % p != 0 for p in range(3, c, 2))
Out[14]: True
确实,41 是一个素数。
所以 prime_list 返回一个素数列表:
In [15]: prime_list(100)
Out[15]: [1, 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]
总结一下,我们简单地使用这个sum()
函数:
In [16]: sum(prime_list(100))
Out[16]: 1061
编辑:根据评论,我尝试了 WillNess 建议的改进和使用集合的真正筛子:
def prime_list(num):
if num < 3:
raise ValueError('this function only accepts arguments > 2')
candidates = range(3, num+1, 2)
L = [c for c in candidates if all(c % p != 0 for p in range(3, c, 2))]
return [1, 2] + L
def prime_list2(num):
if num < 3:
raise ValueError('this function only accepts arguments > 2')
candidates = range(3, num+1, 2)
L = [c for c in candidates if all(c % p != 0 for p in
range(3, int(math.sqrt(c))+1, 2))]
return [1, 2] + L
def prime_list3(num):
candidates = set(range(3, num+1, 2))
results = [1, 2]
while candidates:
t = list(candidates)[0]
results.append(t)
candidates -= set(range(t, num+1, t))
return results
一些时间num=100
:
In [8]: %timeit prime_list(100)
1000 loops, best of 3: 180 us per loop
In [9]: %timeit prime_list2(100)
1000 loops, best of 3: 192 us per loop
In [10]: %timeit prime_list3(100)
10000 loops, best of 3: 83.9 us per loop
并且num=1000
:
In [11]: %timeit prime_list(1000)
100 loops, best of 3: 8.05 ms per loop
In [12]: %timeit prime_list2(1000)
100 loops, best of 3: 2.43 ms per loop
In [13]: %timeit prime_list3(1000)
1000 loops, best of 3: 1.26 ms per loop
num = 5000
:
In [14]: %timeit prime_list(5000)
1 loops, best of 3: 166 ms per loop
In [15]: %timeit prime_list2(5000)
100 loops, best of 3: 11.1 ms per loop
In [16]: %timeit prime_list3(5000)
100 loops, best of 3: 15.3 ms per loop
最后num=50000
:
In [18]: %timeit prime_list3(50000)
1 loops, best of 3: 1.49 s per loop
In [19]: %timeit prime_list2(50000)
1 loops, best of 3: 170 ms per loop