0

I have this function for calculate prime numbers with sieve of eratosthenes. I have one error i don't understand why.

def era1(n):

    llista1 = []
    llista2 = []
    i = 2

    while(i<(n+1)):
        llista1.append(i)
        i = i + 1

    while (llista1[0]<(n**0.5)):
        llista2.append(llista1[0])    
        for j in range ((len(llista1))-1):
            if (llista1[j] % llista1[0] == 0) :  #<------- error list index out of range
                llista1.remove(llista1[j])
        llista1.remove(llista1[0])
    print llista2
Kaushik NP
  • 6,733
  • 9
  • 31
  • 60
  • 1
    I recommend renaming your variables so the code is clearer. In particular, the two lists could be called, for example, "unsievedNumbersList" and "sievedNumbersList". Something that describes what they are better. – Colm Bhandal Oct 15 '17 at 11:59

2 Answers2

2

This is the result of removing items in a list while iterating through them. You've specified your for loop to run for n amount of times, but by the time you get to the nth item, the item which was once there has been moved back a few indexes because you're removing items from the list.

You'll need to re-think your method in reimplementing the Sieve. I can't 100% follow your approach to it, but I'm sure it might involve having a secondary list. Whitelist, don't blacklist :).

Also, enumerate() is a cool function to look into.

TerryA
  • 58,805
  • 11
  • 114
  • 143
  • 1
    Interesting- would removing things every iteration also cause efficiency problems in that case, since the indices have to be recalculated all the time? – Colm Bhandal Oct 15 '17 at 12:00
  • @ColmBhandal If you were to recalculate the indexes, then yes of course. However, this should really be avoided since there would always be a better way to fix it. Python makes no attempt to recalculate indexes (hence the IndexError) – TerryA Oct 15 '17 at 12:01
  • @Terry , how does `enumerate` help here? Does it create a shallow copy? – Kaushik NP Oct 15 '17 at 12:08
  • @TerryA I guess what I was asking was this. When you index a list in Python, how does Python know what element to retrieve if you've removed stuff before that element? E.g. I have letters = {A, B, C, D, E}. If I do letters[3] I get D. Then I do letters.remove(C). And now when I index letters[3] I get E. How does Python know that letters[3] is now E, vs. D, without having to do some computation to shift the indices down? – Colm Bhandal Oct 15 '17 at 12:17
  • @KaushikNP Oh, I just brought up `enumerate()` for the sake of not having to do `range(len(...` – TerryA Oct 15 '17 at 12:21
  • @ColmBhandal You ask a very good question, and I've been trying to research it for the past 10-15 minutes and I can't come up with an adequate answer. The [source code for list.remove](https://github.com/python/cpython/blob/master/Objects/listobject.c#L2289) seems to suggest that it slices the list from both directions of the object removed (eg: `L=[1, 2, 3, 4, 5]; L.remove(3) == L[0:2]+L[3:]`) - although I could be wrong here. There is no 'map' for indexing (i.e, Python doesn't know that `letters[2]` was ever `C`, it just finds the 3rd element in the array and returns it). – TerryA Oct 15 '17 at 12:32
  • @ColmBhandal So when one element is removed, "recalculating the indexes" doesn't really exist. Indexing is always the same. The only performance differences would be that `list.remove` is `O(n)`, and calling it multiple times would be slower than generating a new list. – TerryA Oct 15 '17 at 12:35
  • 1
    @TerryA yeah it also seems to imply that retrieval of an item is `O(n)` too, which seems mighty wasteful for something to use inside a for loop. Anyway, if we take a number of steps back, I think your comment says it all: whitelist, don't blacklist! ;) – Colm Bhandal Oct 15 '17 at 12:37
0

might be useful for anyone that still looking for this algorithm approach

def SieveOfEratosthenes(n): 
    # Create a boolean array "prime[0..n]" and initialize 
    # all entries it as true. A value in prime[i] will 
    # finally be false if i is Not a prime, else true. 
    prime = [True for i in range(n + 1)] 
    p = 2
    while (p * p <= n): 
            
        # If prime[p] is not changed, then it is a prime 
        if (prime[p] == True): 
                
            # Update all multiples of p 
            for i in range(p * 2, n + 1, p): 
                prime[i] = False
        p += 1
    prime[0]= False
    prime[1]= False
    # Print all prime numbers 
    for p in range(n + 1): 
        if prime[p]: 
            print (p) 
    
# driver program 
if __name__=='__main__': 
    n = 30
    print ("Following are the prime numbers smaller") 
    print ("than or equal to", n )
    SieveOfEratosthenes(n) 
greendino
  • 416
  • 3
  • 17