Python- Sieve of Eratosthenes- Compact Python

后端 未结 8 1156
醉话见心
醉话见心 2021-01-06 14:09

This is my code for finding primes using the Sieve of Eratosthenes.

list = [i for i in range(2, int(raw_input(\"Compute primes up to what number? \"))+1)]  
         


        
相关标签:
8条回答
  • 2021-01-06 14:16

    Here's a simple demonstration of the sieve. Note that lambda isn't used as the filtering function, because the prime number needs to bound at definition time. Also of interest is that it's efficient in the sense of not duplicating divisions, but in the long run it could lead to you-know-what.

    import itertools
    
    def primes():
        ints = itertools.count(2)
        while True:
            p = next(ints)
            yield p
            ints = itertools.ifilter(p.__rmod__, ints)
    
    print list(itertools.islice(primes(), 10))
    # [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
    
    0 讨论(0)
  • 2021-01-06 14:18

    It's not precisely a direct translation of your loops, but it's quite close and compact:

    >>> l = range(2, 101)
    >>> sorted(set(l).difference(a for i in l for a in l if a!=i and a%i == 0))
    [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]
    

    Although I'd suggest a > i rather than a != 0 as being shorter and faster ;)

    0 讨论(0)
  • 2021-01-06 14:21

    The first thing to note is that what you have written is not the sieve of eratosthenes. Look how many loops a totally naive sieve of eratosthenes executes:

    def sieve1(n):
        loops = 0
        numbers = set(range(2, n))
        for i in range(2, int(n ** 0.5) + 1):
            for j in range(i * 2, n, i):
                numbers.discard(j)
                loops += 1
        return sorted(numbers), loops
    

    Tested:

    >>> sieve1(100)
    ([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], 
     178)
    

    178 loops for 100 numbers (not including the sort). This can be improved with a few minor changes:

    def sieve2(n):
        loops = 0
        numbers = range(0, n)
        for prime in numbers:
            if prime < 2:
                continue
            elif prime > n ** 0.5:
                break
            for i in range(prime ** 2, n, prime):
                numbers[i] = 0
                loops += 1
        return [x for x in numbers if x > 1], loops
    

    Tested:

    >>> sieve2(100)
    ([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], 
     102)
    

    102 loops for 100 numbers (not including the filter at the end). Now look at yours:

    def sieve3(n):
        loops = 0
        numbers = range(2, n)
        for i in numbers:
            for j in numbers:
                if j != i and j % i == 0:
                    numbers.remove(j)
                loops += 1
        return numbers, loops
    

    Tested:

    >>> sieve3(100)
    ([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], 
     663)
    

    It gets worse:

    >>> [sieve1(x)[1] for x in [100, 1000, 10000]]
    [178, 2978, 41723]
    >>> [sieve2(x)[1] for x in [100, 1000, 10000]]
    [102, 1409, 16979]
    >>> [sieve3(x)[1] for x in [100, 1000, 10000]]
    [663, 28986, 1523699]
    

    At n = 10000, your implementation does almost 100x as much work!

    My suggestion would be to create a sensible implementation before making it "compact." Code golf can be fun, but it's nowhere near as challenging or as edifying as writing efficient code, whatever the length.

    That said, consider this one-liner (if you don't count the import, which you could get rid of by using lambda x, y: x - y in place of operator.sub). This implements the first algorithm with a small improvement:

    >>> from operator import sub
    >>> reduce(sub, (set(range(x ** 2, 100, x)) for x in range(2, int(100 ** 0.5) + 1)), set(range(2, 100)))
    set([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])
    
    0 讨论(0)
  • 2021-01-06 14:21

    You are not doing the Sieve of Eratosthenes; the danger of not properly implementing the algorithm is that it will be extremely slow. Try your algorithm on 10**6 for example.

    Shortest implementation of the bounded Sieve of Eratosthenes I can come up with:

    def primes(upTo):
        isPrime = list(range(upTo))
        for p in range(2,int(upTo**0.5)+1): #p: 2,3,4,...,sqrt(N)
            print(p, isPrime[p])
            if isPrime[p]:
                for multiple in range(p**2,upTo,p): #mult: p^2, p^2+p, p^2+2p, ..., N
                    isPrime[multiple] = False
        return [x for x in isPrime[2:] if x]
    

    Demo:

    >>> list(primes(29))
    [2, 3, 5, 7, 11, 13, 17, 19, 23]
    

    It's actually rather succinct, if you ignore linebreaks and the massive skip-even-numbers optimization:

    isPrime=[True]*upTo for p in range(2,upTo): if isPrime[p]: yield p for m in range(p,upTo,p): isPrime[m]=False
    
    0 讨论(0)
  • 2021-01-06 14:27

    Not exactly the the most compact solution, but the step argument in the range function in Python3 helps here -

    prime_sieve = [True] * (int(input('Primes Upto ?'))+1)
    # The first prime number
    for i in range(2, len(prime_sieve)):
        if prime_sieve[i]:
            for j in range(i+i, len(prime_sieve), i):
                prime_sieve[j] = False
            print(i, end=',')
    
    0 讨论(0)
  • 2021-01-06 14:30
    def sieve(n):
        sieve_list = range(n)
        zero_list = [0] * n
        for i in range(2, int(n**.5) + 1):
            if sieve_list[i]:
                sieve_list[2*i:n:i] = zero_list[2*i:n:i]
        return filter(None, sieve_list)[1:]
    
    0 讨论(0)
提交回复
热议问题