5 Best Ways to Generate a List of Primes Less Than n in Python

Rate this post

πŸ’‘ Problem Formulation: Generating a list of prime numbers less than a given value n is a common task in algorithm design and number theory. Primes are numbers greater than 1 that have no divisors other than 1 and themselves. For example, if n = 10, the output should be a list of prime numbers less than 10, which are [2, 3, 5, 7].

Method 1: Trial Division

Trial Division is a straightforward method of generating a list of prime numbers. Iterate through each number up to n and check for primality by dividing by all integers up to its square root. If the number is only divisible by 1 and itself, it’s prime.

Here’s an example:

def is_prime(num):
    if num < 2:
        return False
    for i in range(2, int(num**0.5)+1):
        if num % i == 0:
            return False
    return True

def generate_primes(n):
    return [x for x in range(2, n) if is_prime(x)]

# Example usage
primes = generate_primes(10)
print(primes)

Output:

[2, 3, 5, 7]

This method uses a helper function is_prime() to evaluate the primality of each number under n. The list comprehension in generate_primes() iterates through the range and applies is_prime() to filter out non-prime numbers.

Method 2: Sieve of Eratosthenes

The Sieve of Eratosthenes is an efficient algorithm for finding all prime numbers up to any given limit. It works by iteratively marking the multiples of each prime number starting from 2.

Here’s an example:

def sieve_of_eratosthenes(n):
    sieve = [True] * n
    for i in range(2, int(n**0.5) + 1):
        if sieve[i]:
            for j in range(i*i, n, i):
                sieve[j] = False
    return [i for i in range(2, n) if sieve[i]]

# Example usage
primes = sieve_of_eratosthenes(10)
print(primes)

Output:

[2, 3, 5, 7]

This code initializes a list sieve that assumes all numbers are prime (True). It then zeroes out multiples of each found prime starting from 2, effectively ‘sieving’ out non-prime numbers.

Method 3: Sieve of Sundaram

The Sieve of Sundaram is a variation of the sieve method which eliminates numbers of the form i + j + 2ij from the list to find primes up to 2n + 2.

Here’s an example:

def sieve_of_sundaram(n):
    n_new = (n - 1) // 2
    sieve = [True] * (n_new+1)
    for i in range(1, n_new+1):
        j = i
        while i + j + 2*i*j <= n_new:
            sieve[i + j + 2*i*j] = False
            j += 1
    return [2] + [2*i+1 for i in range(1, n_new+1) if sieve[i]]

# Example usage
primes = sieve_of_sundaram(10)
print(primes)

Output:

[2, 3, 5, 7]

The Sieve of Sundaram code marks false in the sieve list for numbers following the formula i + j + 2ij. The remaining numbers are then doubled and incremented by 1 to find the primes (except for the number 2, which is handled separately).

Method 4: Wheel Factorization

Wheel Factorization builds upon the sieve method by skipping numbers that are multiples of the first few primes. This allows the algorithm to iterate only through numbers that have a chance of being prime.

Here’s an example:

def wheel_factorization(n):
    if n < 2:
        return []
    primes = [2]
    # Skip even numbers
    sieve = {i: False for i in range(3, n, 2)}
    for i in sieve:
        if sieve[i]:
            continue
        primes.append(i)
        for j in range(i*i, n, i*2):  # i*2 for skipping even multiples
            sieve[j] = True
    return primes

# Example usage
primes = wheel_factorization(10)
print(primes)

Output:

[2, 3, 5, 7]

Wheel factorization begins by adding 2 to the list of primes and then uses a dictionary comprehension to create a sieve while skipping all even numbers. It then proceeds by marking off non-prime numbers by their odd multiples.

Bonus One-Liner Method 5: Using List Comprehension and all()

A concise one-liner using list comprehensions and the all() function can also generate primes. This utilizes the idea that prime numbers have no divisors other than 1 and themselves.

Here’s an example:

primes = [x for x in range(2, 10) if all(x % y != 0 for y in range(2, int(x**0.5) + 1))]
print(primes)

Output:

[2, 3, 5, 7]

This one-liner filters the range from 2 to n using a list comprehension that includes a number x if all() confirms that no divisor y in the range from 2 to the square root of x divides x.

Summary/Discussion

  • Method 1: Trial Division. Simple and easy to understand. Not the most efficient for larger values of n due to repeated primality testing. Suitable for small ranges of n.
  • Method 2: Sieve of Eratosthenes. Highly efficient for large ranges. Requires more memory for the sieve array. Excellent for generating all primes up to a large n.
  • Method 3: Sieve of Sundaram. Less known but still an efficient sieving method. It requires half the memory of the Sieve of Eratosthenes but has a slightly more complex implementation.
  • Method 4: Wheel Factorization. Enhanced sieve method avoiding multiples of known primes. Cuts down on the number of iterations. Good balance between memory usage and computation time.
  • Bonus Method 5: List Comprehension with all(). Elegant and compact. Best suited for generating primes in a small range. Not efficient for large values of n due to quadratic performance.