首先,这是HOMEWORK,我目前正在研究python上的Eratosthenes Sieve。 我的程序看起来像:
x=[]
for i in range(2,100):
x.append(i)
primes=[]
i=2
while len(x)!=0:
k=x[0]
x.pop(0)
primes.append(k)
while k*i in x:
x.remove(k*i)
i+=1
print(primes)
print(x)
当我的程序打印'primes'时,我得到:
[2, 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]
为什么列表中有复合数字?看起来程序应该可行
#编辑程序,现在看起来:
x=[]
for i in range(2,100):
x.append(i)
primes=[]
while len(x)!=0:
i=2
k=x[0]
x.pop(0)
primes.append(k)
while k*i<=max(x):
x.remove(k*i)
i+=1
if k*i not in x:
i+=1
print('primes','\n',primes,sep='')
print('x','\n',x,sep='')
仍然无法正常工作,收到错误; “ValueError:list.remove(x):x不在列表中”
答案 0 :(得分:2)
一个问题是您只需添加到i
。每次从列表中弹出另一个元素时,您需要将i
重置为2.
也就是说,首先你从列表中弹出2。您逐渐增加i
以从列表中删除所有2的倍数。最后,i
将为50.然后您返回并从列表中弹出3,i
仍为50,因此它只在列表中查找50*3
即使你解决了这个问题,它仍然无效,因为一旦找到不在列表中的一个,你就会停止查看i
值。但k*i
可能不在列表中但k*(i+1)
是 - 例如,在你设置2的倍数后,3的第一个倍数(即6)不在列表中,但下一个(即9)是。所以你不能停下来,直到你尝试每个倍数到列表最大值。
答案 1 :(得分:1)
评论:
这是一个使用位列表的工作和快速筛子: http://stromberg.dnsalias.org/svn/sieve/trunk/
答案 2 :(得分:1)
你应该接受@BrenBarn的答案,因为它涵盖了重要的东西。但是这里有一些提示:
x
列表。让Python为你做。只需将range()
包裹在list()
中,就像这样:
MAX_NUM = 100
x = list(range(2, MAX_NUM))
我们稍后会有更多机会使用MAX_NUM
;请继续阅读。
for
循环range()
而不是while
循环添加到索引变量。而不是:
i = 2
while k*i <= max(x):
# do stuff with k*i
i += 1
试试这个:
for i in range(k*2, max(x), k):
# do stuff with i
Python内置range()
将为您创建一系列值,从k*2
开始,每次添加k
,并以k
的最后一个数字停止}小于max(x)
。现在你的循环运行得更快,你避免了一堆倍数。
x[0]
编入索引以获取k
,然后使用x.pop()
来放弃k
中的x
值,而是采用更简单的方式。 list.pop()
返回弹出的值。所以你可以在一行中这样做:
k = x.pop()
max(x)
。但您已经知道x
中的最大数字,因为您构建了x
。在构建x
时,您可以将最高数字保存在变量中,并使用此变量而不是一遍又一遍地查找max(x)
。关于max(x)
的好处是它不会检查已被拔出的数字;例如,当k
为3时,将删除99。但max(x)
价格昂贵,所以我认为仅使用保存的价值总体上是一个胜利。这就是我保存MAX_NUM
的原因。所以你可以这样做:
for i in range(k*2, MAX_NUM, k):
# do stuff with i
set()
类,但它对这个问题有好处。正如dstromberg在他/她的回答中所说,x.remove(some_value)
在x
包含许多值时很慢。但是从set
中删除值总是非常快速的操作。你可以建立一个这样的集合:
x = set(range(2, 100))
此集将包含2到99之间的所有整数值。
然后,关于集合的一个简洁的事情:你可以摆脱成员而不用检查它们是否在集合中,使用.discard()
成员函数(另一个便宜的事情与{ {1}})。
set
实际上,# list solution
if i in my_list:
my_list.remove(i)
# set solution
my_set.discard(i)
(在列表中使用)和in
都很昂贵。所以list.remove()
用一个廉价的操作取代了两个昂贵的操作!
将原始程序置于工作状态后,请保留原始程序的副本,然后重写该程序以使用set
代替set
。将最大整数从100增加到,比如说10000和两个程序的时间。你应该注意到差异。 list
需要的时间比set
长,但您可以在操作(list
测试或删除值)上赢得大量时间。
in
无法编入索引,因此set
将无法正常工作......如何查找x[0]
?”我建议您只使用带有k
语句的for
循环来生成所需的range()
值。您可以执行以下操作,而不是查看k
或使用x[0]
:
k = x.pop()
使用for k in range(2, MAX_NUM):
if k not in x:
continue
set
测试非常快,因此这将很快跳过所有非素数。它不像你的原始程序总是有下一个准备好的方式那样聪明,但总的来说我认为in
是这个问题的胜利。
哦,嘿,我们可以再次使用set
。
MAX_NUM
没有set
所以如何在筛子结束时获取素数列表?”再好不过了!
.pop()
所以筛选掉非素数,然后在完成后取出素数列表。
您可能希望使用稍微好一点的变量名称。我个人喜欢简洁的单字母变量,如果它们用在紧凑的代码中,那么我会保留result = list(my_set) # get a list of values stored in my_set
,但i
可能x
和sieve
应该是k
或其他什么。
我很高兴看到您了解如何使用next_prime
功能的更高级功能,但我认为您的打印代码可能更简单。
而不是:
print()
试试这个:
print('primes','\n',primes,sep='')
或许这个:
print('primes')
print(primes)
使用上述所有建议来计算Eratosthenes筛选的实际程序比建议的要短得多!我有它的书面和测试,但我不会发布它,除非你希望我这样做。我的解决方案(不包括print('primes:\n{}'.format(primes))
调用或空行)是8行Python,第一行是:print()
(编辑:这是六行,但我没有检查到看看MAX_NUM = 100
是否在集合中,所以它很慢。检查又增加了两行。)
完成后,将原件与修改后的原件进行比较。你更倾向哪个?有人比其他人更容易理解吗?
我喜欢Python的一个方面是,当程序有效地使用Python的内置功能时,它会变得更简单,更漂亮,更容易理解。
祝你好运,玩得开心!