简体   繁体   中英

Python list.remove for loop “x not in list”

I'm trying to create a prime sieve in Python.

I start with making a list from 2 to 2000. I want to iterate through all primes with a check, and remove all multiples of the primes from the list.

I've not gotten around the loop for primes yet, but what I do have a method to start with the number 2, and remove all its multiples.

primes=list(range(2,2001))
p=2

while p<len(primes):
    for x in range (p*p, len(primes), p):
        primes.remove(x)
    print(primes)

this prints: [...] 1989, 1991, 1993, 1995, 1997, 1999, 2000]

As you can see, the number 2000 is still there, and it should not be.

Traceback (most recent call last):
  File "C:/Users/Are/PycharmProjects/Project Euler/10.py", line 8, in <module>
    primes.remove(x)
ValueError: list.remove(x): x not in list

What's wrong with my reasoning?

I'm using PyCharm, is there a way for me to print the value for x at the time of the error?

your list is not 2000 long, you start at 2..

>>> primes=list(range(2,2001))
>>> print len(primes)
1999

So when you do the while loop, it doesn't get up to 2000... :)

You create a list of 1999 elements:

>>> len(range(2,2001))
1999

You then loop over a range() up to, but not including, that length:

for x in range (p*p, len(primes), p):

Thus x is never going to be larger than 1998.

Instead of len(primes) , use an upper limit constant:

limit = 2001
primes=list(range(limit))

# ...

for x in range (p*p, limit, p):

Next problem is that you continue to loop with while p<len(primes): ; you will generate numbers that are no longer part of the primes list, so they cannot be removed a second time. You can use exception handler to catch the exception:

try:
    primes.remove(x)
except ValueError:
    # already removed
    pass

but you may want to rethink the while loop condition.

In a range(a,b) the first value is a and the last value is b-1 . In your case, that means you are only iterating up to len(primes)-1 , which is less than 2000 .

The value of x at the time of the crash is actually 4. You don't increment p to the next value in the list at the end of the first loop.

Second, you're trying to remove values multiple times from the list. You will (for instance) attempt to remove 12 twice. Once when you're iterating through on 2, once when you're iterating on 3.

Finally, you're going by the length of the list, which is always getting smaller as you remove values from it. Your first time around the loop and your list size is very small indeed.

Reworking your code:

primes=list(range(2,2001))
p=2

while p<2000:
    for x in range (p*p, 2001, p):
        if x in primes:
            primes.remove(x)
    while 1:
        p = p + 1
        if p in primes or p > 2000:
            break

print primes

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM