I am practicing list comprehensions and nested list comprehensions. As part of my practice I am writing out equivalent for loops. This for loop I cannot get right, and I believe it's because I'm trying to assign a value rather than a variable in a function call. The error I receive is:
File "<stdin>", line 4
SyntaxError: can't assign to function call
The code I have written for this loop is:
import math
def squared_primes():
list = []
for x in range(1,1000000):
for q in range(2,math.sqrt(x)+1):
if all(x % q != 0):
list.append(x**2)
print(list)
This function is trying to create a list of perfect squares whose roots are prime numbers in the range 1 to 1000000.
Can someone help me understand where exactly the syntax of my loop breaks down? Also, can I possibly do this as a nested list comprehension? Clearly my list comprehension is breaking down because I can't get my for loop syntax right...
SOLUTION: Thanks to user @Evan, I was able to fix the variable and syntax problems, and took some cues about how to fix the all()
statement from this thread.
This code will properly return a list of the squared primes from 1,1000:
def squared_primes():
list1 = []
for x in range(1,1000):
if all(x%q !=0 for q in range(2,int(math.sqrt(x)+1))):
list1.append(x**2)
print(list1)
This code will properly return a list of the squared primes from 1,1000:
Except that it returns 1 as the first element of the list and 1's square root isn't a prime. Let's fix that glitch and rewrite the code as a proper function:
from math import sqrt
def squared_primes(maximum):
primes = []
for number in range(2, maximum):
if all(number % divisor != 0 for divisor in range(2, int(sqrt(number)) + 1)):
primes.append(number ** 2)
return primes
print(squared_primes(1000))
BTW, this is not a list comprehension:
all(x % q !=0 for q in range(2, int(math.sqrt(x) + 1)))
it's a generator! If you wanted a list comprehension you would have done:
all([x % q !=0 for q in range(2, int(math.sqrt(x) + 1))])
but stick with the generator as it fails composites with less effort.
Your code will start to bog down when we ask for a list of the squares up to 1000000 (a million) or more. That's when we'll want a more efficient sieve-based algorithm like:
def squared_primes(maximum):
sieve = [True] * maximum
if maximum > 0:
sieve[0] = False # zero is not a prime
if maximum > 1:
sieve[1] = False # one is not a prime
for index in range(2, int(maximum ** 0.5) + 1):
if sieve[index]:
prime = index
for multiple in range(prime + prime, maximum, prime):
sieve[multiple] = False
return [index * index for index in range(maximum) if sieve[index]]
At around a million, this code will return results about 20x faster than your division-based solution.
And @Evan's glorious comprehension, since it lacks your math.sqrt()
optimization, will be orders of magnitude slower than either (I'm still waiting for it to finish for one million) and starts the list with two incorrect results. We can put it on a par time-wise with your revised code by doing:
from math import sqrt
def squared_primes(maximum):
return [number ** 2 for number in range(2, maximum) if all(number % divisor for divisor in range(2, int(sqrt(number)) + 1))]
print(squared_primes(1000))
And this is a list comprehension. But again, the wrong approach so go back and look at the sieve-based implementation.