First, you're using a really weird, inefficient way to record whether something is composite. You don't need to store string representations of the numbers, or even the numbers themselves. You can just use a big list of booleans, where prime[n]
is true if n
is prime.
Second, there's no reason to worry about wasting a bit of space at the beginning of the list if it simplifies indexing. It's tiny compared to the space taken by the rest of the list, let alone all the strings and ints and stuff you were using. It's like saving $3 on paint for your $300,000 car.
Third, range
takes a step
parameter you can use to simplify your loops.
def sieve(n):
"""Returns a list of primes less than n."""
# n-long list, all entries initially True
# prime[n] is True if we haven't found a factor of n yet.
prime = [True]*n
# 0 and 1 aren't prime
prime[0], prime[1] = False, False
for i in range(2, n):
if prime[i]:
# Loop from i*2 to n, in increments of i.
# In other words, go through the multiples of i.
for j in range(i*2, n, i):
prime[j] = False
return [x for x, x_is_prime in enumerate(prime) if x_is_prime]