Python 3 - 迭代时从列表中删除元素(Eratosthenes 筛法)
Python 3 - removing elements from a list while iterating (sieve of Eratosthenes)
我正在构建一个程序,使用 python 使用 Eratosthenes 筛法查找所有小于数字 n 的素数。
该算法首先创建一个从 2 到 n 的数字列表,然后遍历该列表,删除第一个可用元素和相应的倍数。问题是我这样做似乎没有得到正确的结果。我也很感激任何改进性能的建议。
这是算法:
def primes(max):
'''The sieve of Eratosthenes
Algorithm to find all primes smaller than max'''
init = time.clock()
allNum = [a for a in range(2, max+1)]
primes = []
for n in allNum:
# remove all multiples of prime n
toRemove = (a for a in range(n, max+1, n) if a in allNum)
for i in toRemove:
print('toRemove:', i)
allNum.remove(i)
# add the prime to the list
primes.append(n)
deltaT = time.clock() - init
print('Time taken to process:', deltaT)
return primes
(已解决)我是这样改的:
while len(allNum) != 0:
prime = allNum[0]
# remove all multiples of prime
toRemove = (a for a in range(prime, max+1, prime) if a in allNum)
for i in toRemove:
print('toRemove:', i)
allNum.remove(i)
# add the prime to the list
primes.append(prime)
我认为您无法在遍历列表时更改它。
您可以切换到 while 循环,只要您的原始列表中还有任何数字,该循环就会运行。对于每次迭代,您至少删除第一个数字:如果它是质数,则将其移至您的质数列表,如果不是,则将其及其所有倍数删除。
当您遍历列表时,您引用的是每个偏移量,而不是每个值。例如,当您获得第一个结果时,如果它限定并删除该值,则所有后续值都会向前滑动并且您的偏移量会增加。您的偏移量现在是索引 1(基数 0)。但是你刚刚删除了索引 0,一切都向前滑动了。您基本上跳过了第二个数字。
0$ python3
Python 3.4.8 (default, Mar 23 2018, 10:04:27)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-16)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> [a for a in range(1, 20)]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
>>> the_list = [a for a in range(1, 20)]
>>> for a in the_list:
... the_list.remove(a)
...
>>> the_list
[2, 4, 6, 8, 10, 12, 14, 16, 18]
>>>
另一种更快的替代方法是构建一个布尔值列表(全部为 True)并使用该算法将它们设置为 False。素数是列表中所有保持为真的索引:
def primes(max):
mask = [True for i in range(0,max + 1)]
for num in range(2,max):
if not mask[num]:
continue
for multiple in range(num*2, max+1, num):
mask[multiple] = False
primes = [i for i,mask_value in enumerate(mask) if mask_value]
return primes[2:]
我正在构建一个程序,使用 python 使用 Eratosthenes 筛法查找所有小于数字 n 的素数。 该算法首先创建一个从 2 到 n 的数字列表,然后遍历该列表,删除第一个可用元素和相应的倍数。问题是我这样做似乎没有得到正确的结果。我也很感激任何改进性能的建议。
这是算法:
def primes(max):
'''The sieve of Eratosthenes
Algorithm to find all primes smaller than max'''
init = time.clock()
allNum = [a for a in range(2, max+1)]
primes = []
for n in allNum:
# remove all multiples of prime n
toRemove = (a for a in range(n, max+1, n) if a in allNum)
for i in toRemove:
print('toRemove:', i)
allNum.remove(i)
# add the prime to the list
primes.append(n)
deltaT = time.clock() - init
print('Time taken to process:', deltaT)
return primes
(已解决)我是这样改的:
while len(allNum) != 0:
prime = allNum[0]
# remove all multiples of prime
toRemove = (a for a in range(prime, max+1, prime) if a in allNum)
for i in toRemove:
print('toRemove:', i)
allNum.remove(i)
# add the prime to the list
primes.append(prime)
我认为您无法在遍历列表时更改它。
您可以切换到 while 循环,只要您的原始列表中还有任何数字,该循环就会运行。对于每次迭代,您至少删除第一个数字:如果它是质数,则将其移至您的质数列表,如果不是,则将其及其所有倍数删除。
当您遍历列表时,您引用的是每个偏移量,而不是每个值。例如,当您获得第一个结果时,如果它限定并删除该值,则所有后续值都会向前滑动并且您的偏移量会增加。您的偏移量现在是索引 1(基数 0)。但是你刚刚删除了索引 0,一切都向前滑动了。您基本上跳过了第二个数字。
0$ python3
Python 3.4.8 (default, Mar 23 2018, 10:04:27)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-16)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> [a for a in range(1, 20)]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
>>> the_list = [a for a in range(1, 20)]
>>> for a in the_list:
... the_list.remove(a)
...
>>> the_list
[2, 4, 6, 8, 10, 12, 14, 16, 18]
>>>
另一种更快的替代方法是构建一个布尔值列表(全部为 True)并使用该算法将它们设置为 False。素数是列表中所有保持为真的索引:
def primes(max):
mask = [True for i in range(0,max + 1)]
for num in range(2,max):
if not mask[num]:
continue
for multiple in range(num*2, max+1, num):
mask[multiple] = False
primes = [i for i,mask_value in enumerate(mask) if mask_value]
return primes[2:]