Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 9 months ago.
Improve this question
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.
This is pretty concise. List comprehensions are glorious.
def squared_primes(maximum):
return( [ x**2 for x in range(0,maximum) if all( x % i for i in range(2, x) ) ] )
print(squared_primes(1000000))
Related
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 1 year ago.
Improve this question
I am trying to find the largest prime factor of a number. Below is my code in Python. When I input 600851475143, it doesn't give me an output. Is this code wrong?
def prime(n):
list = []
only_primes = []
for i in range(2,int(n)):
if n%i==0:
list.append(i)
for number in list:
if isprime(number)==True:
only_primes.append(number)
print(max(only_primes))
def isprime(k):
for z in range(2,int(k**1/2)+1):
if k%z==0:
return False
return True
print(prime(600851475143))
There are a couple things wrong here.
Most notably, the indentation on your 2nd for loop is off which is causing that loop to be ran every single iteration of the first for loop. It should be at the same indentation as the first so it can run strictly after.
Your algorithm is still far too slow to compute the largest prime factor of the number 600,851,475,143. It will only run in a feasible amount of time for numbers in the millions range. If you would like to run computations for numbers of that size, you will have to use a more advanced technique.
You are missing parentheses for the exponent in isprime's for loop.
In the case that your input number happens to be prime, your code will crash due to the only_primes list being empty.
Here is a fixed version:
def prime(n):
list = []
only_primes = []
for i in range(2, int(n)):
if n % i == 0:
list.append(i)
for number in list:
if isprime(number):
only_primes.append(number)
if len(only_primes) > 0:
return max(only_primes)
return n
def isprime(k):
for z in range(2, int(k**(1/2) + 1)):
if k % z == 0:
return False
return True
print(prime(1001))
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
divisors = []
def check_for_prime(x):
divisors = [x / d for d in list(range(x)) if x != any([0, 1, x])]
if isinstance(divisors, float):
yield x
When I try to run this code, it shows an error: 'list object cannot be interpreted as an integer'. How can I fix this so the loop can successfully divide everything?
It seems like you are trying to check if a given number is prime through list comprehension. There are a good bunch of things wrong with your logic-
divisors = [x / d for d in list(range(x)) if x != any([0, 1, x])]
I believe you're trying to find a list of divisors for x here. This makes no sense though, even if I assume that you thought x != any([0, 1, x]) means "if x is either 0, 1, or x" (that's not actually what this code means). Wouldn't that statement always be true? I mean x has got to be x (unless it's nan, but that's a different topic).
If you wanted to express "if x is either 0, 1 or x" in python, you'd use if x in [0, 1, x] (you shouldn't want to though since that makes 0 sense as explained above). Not any. Read what any does.
To get a list of divisors for x, you should instead do-
divisors = [d for d in range(2, math.floor(x/2) + 1) if x % d == 0]
Essentially, you start from 2 (not 0 because that's impossible, and not 1 because we want to avoid that for prime checking), and stop at half the given number (because after that point, you can't divide the given number and get an integral result). Throughout this range, you only add those d for which x % d is 0. I.E, the result is integral. Notice, 6 % 3 is 0, because 3 is indeed a divisor of 6.
I have 0 clue what the hell you're trying to do here though-
if isinstance(divisors, float):
yield x
You're checking whether or not divisors is a float? why? you already know it's a list, you made it in the previous line.
I think you want to know if the given number is a prime or not. In that case, you can just check if the length of divisors is more than 0.
return len(divisors) > 0
Edit: As #RiccardoBucco mentioned below. If you don't want the list of divisors at all, you can simply return as soon as you find a divisor. A simple loop will suffice for that.
for d in range(2, math.floor(x/2) + 1):
if x % d == 0:
# x is not prime
return False
# x is prime
return True
However, DO NOT forget to factor in the exceptional case when x = 1, 1 is not a prime number. Should be factored in both the for loop and the list comprehension method.
You are passing your list as the input argument to range, which expects an integer. Don't do that. Say for i in list.
This will always fail because you're creating a new list by using the comprehension in line 3. Line 4 will always evaluate to False because a list is obviously not a float.
I'm trying to complete the following challenge: https://app.codesignal.com/challenge/ZGBMLJXrFfomwYiPs.
I have written code that appears to work, however, it is so inefficient that it fails the test (too long to execute and uses too much memory). Are there any ways I can make this more efficient? I'm quite new to building efficient scripts. Someone mentioned "map()" can be used in lieu of "for i in range(1, n)". Thank you Xero Smith and others for the suggestions of optimising it this far:
from functools import reduce
from operator import mul
from itertools import combinations
# Starting from the maximum, we can divide our bag combinations to see the total number of integer factors
def prime_factors(n):
p = 2
dct = {}
while n != 1:
if n % p:
p += 1
else:
dct[p] = dct.get(p, 0) + 1
n = n//p
return dct
def number_of_factors(n):
return reduce(mul, (i+1 for i in prime_factors(n).values()), 1)
def kinderLevon(bags):
candies = list()
for x in (combinations(bags, i) for i in range(1, len(bags)+1)):
for j in x:
candies.append(sum(j))
satisfied_kids = [number_of_factors(i) for i in candies]
return candies[satisfied_kids.index(max(satisfied_kids))]
Any help would be greatly appreciated.
Thanks,
Aaron
Following my comment, I can already identify a memory & complexity improvement. In your factors function since you only need the number of factors, you could only count them instead of storing them.
def factors(n):
k = 2
for i in range(2, n//2 +1):
if n % i == 0:
k += 1
return k
EDIT: as suggested in the comments stop the counter earlier.
This actually reduces time complexity for huge numbers, but not really for smaller ones.
This is a much better improvement than the one using list comprehensions (that still allocates memory)
Moreover, it is pointless to allocate your combinations list twice. You're doing
x = list(combinations(bags, i));
for j in list(x):
...
The first line you convert a tuple (returned by combinations) into a list, hence duplicating the data. The second line list(x) re-allocates a copy of the list, taking even more memory! There you should really just write:
for j in combination(bags, i):
...
As a matter of syntax, please don't use semicolons ; in Python !
First things first, combinations are iterable. This means you do not have to convert them into lists before you iterate over them; infact it is terribly inefficient to do so.
Next thing that can be improved significantly is your factors procedure. Currently it is linear. We can do better. We can get the number of factors of an integer N via the following algorithm:
get the prime factorisation of Nsuch that N = p1^n1 * p2^n2 * ...
the number of factors of N is (1+n1) * (1+n2) * ...
see https://www.wikihow.com/Find-How-Many-Factors-Are-in-a-Number for details.
Something else, your current solution has a lot of variables and computations that are not used. Get rid of them.
With these, we get the following which should work:
from functools import reduce
from operator import mul
from itertools import combinations
# Starting from the maximum, we can divide our bag combinations to see the total number of integer factors
def prime_factors(n):
p = 2
dct = {}
while n != 1:
if n % p:
p += 1
else:
dct[p] = dct.get(p, 0) + 1
n = n//p
return dct
def number_of_factors(n):
return reduce(mul, (i+1 for i in prime_factors(n).values()), 1)
def kinderLevon(bags):
candies = list()
for x in (combinations(bags, i) for i in range(1, len(bags)+1)):
for j in x:
candies.append(sum(j))
satisfied_kids = [number_of_factors(i) for i in candies]
return candies[satisfied_kids.index(max(satisfied_kids))]
Use list comprehensions. The factors function can be transformed like this :
def factors(n):
return len([i for i in range(1, n + 1) if n % i == 0])
I currently have ↓ set as my randprime(p,q) function. Is there any way to condense this, via something like a genexp or listcomp? Here's my function:
n = randint(p, q)
while not isPrime(n):
n = randint(p, q)
It's better to just generate the list of primes, and then choose from that line.
As is, with your code there is the slim chance that it will hit an infinite loop, either if there are no primes in the interval or if randint always picks a non-prime then the while loop will never end.
So this is probably shorter and less troublesome:
import random
primes = [i for i in range(p,q) if isPrime(i)]
n = random.choice(primes)
The other advantage of this is there is no chance of deadlock if there are no primes in the interval. As stated this can be slow depending on the range, so it would be quicker if you cached the primes ahead of time:
# initialising primes
minPrime = 0
maxPrime = 1000
cached_primes = [i for i in range(minPrime,maxPrime) if isPrime(i)]
#elsewhere in the code
import random
n = random.choice([i for i in cached_primes if p<i<q])
Again, further optimisations are possible, but are very much dependant on your actual code... and you know what they say about premature optimisations.
Here is a script written in python to generate n random prime integers between tow given integers:
import numpy as np
def getRandomPrimeInteger(bounds):
for i in range(bounds.__len__()-1):
if bounds[i + 1] > bounds[i]:
x = bounds[i] + np.random.randint(bounds[i+1]-bounds[i])
if isPrime(x):
return x
else:
if isPrime(bounds[i]):
return bounds[i]
if isPrime(bounds[i + 1]):
return bounds[i + 1]
newBounds = [0 for i in range(2*bounds.__len__() - 1)]
newBounds[0] = bounds[0]
for i in range(1, bounds.__len__()):
newBounds[2*i-1] = int((bounds[i-1] + bounds[i])/2)
newBounds[2*i] = bounds[i]
return getRandomPrimeInteger(newBounds)
def isPrime(x):
count = 0
for i in range(int(x/2)):
if x % (i+1) == 0:
count = count+1
return count == 1
#ex: get 50 random prime integers between 100 and 10000:
bounds = [100, 10000]
for i in range(50):
x = getRandomPrimeInteger(bounds)
print(x)
So it would be great if you could use an iterator to give the integers from p to q in random order (without replacement). I haven't been able to find a way to do that. The following will give random integers in that range and will skip anything that it's tested already.
import random
fail = False
tested = set([])
n = random.randint(p,q)
while not isPrime(n):
tested.add(n)
if len(tested) == p-q+1:
fail = True
break
while n in s:
n = random.randint(p,q)
if fail:
print 'I failed'
else:
print n, ' is prime'
The big advantage of this is that if say the range you're testing is just (14,15), your code would run forever. This code is guaranteed to produce an answer if such a prime exists, and tell you there isn't one if such a prime does not exist. You can obviously make this more compact, but I'm trying to show the logic.
next(i for i in itertools.imap(lambda x: random.randint(p,q)|1,itertools.count()) if isPrime(i))
This starts with itertools.count() - this gives an infinite set.
Each number is mapped to a new random number in the range, by itertools.imap(). imap is like map, but returns an iterator, rather than a list - we don't want to generate a list of inifinite random numbers!
Then, the first matching number is found, and returned.
Works efficiently, even if p and q are very far apart - e.g. 1 and 10**30, which generating a full list won't do!
By the way, this is not more efficient than your code above, and is a lot more difficult to understand at a glance - please have some consideration for the next programmer to have to read your code, and just do it as you did above. That programmer might be you in six months, when you've forgotten what this code was supposed to do!
P.S - in practice, you might want to replace count() with xrange (NOT range!) e.g. xrange((p-q)**1.5+20) to do no more than that number of attempts (balanced between limited tests for small ranges and large ranges, and has no more than 1/2% chance of failing if it could succeed), otherwise, as was suggested in another post, you might loop forever.
PPS - improvement: replaced random.randint(p,q) with random.randint(p,q)|1 - this makes the code twice as efficient, but eliminates the possibility that the result will be 2.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 9 years ago.
Improve this question
Recently I found a puzzle that required me to list all cyclic primes below a number.
In this context cyclic means that if we rotate the digits it is still prime:
eg.
1193 is prime
1931 is prime
9311 is prime
3119 is prime
This is the code I origanly wrote:
a=[]
upto=1000000
for x in range(upto):
a.append([x,0])
print('generated table')
a[1][1]=1
a[0][1]=1
for n in range(2,int(math.sqrt(upto))):
for k in range(2,(int(upto/n)+2)):
try:
a[n*k][1]=1
except IndexError:
pass
print('sive complete')
p=[]
for e in a:
if (e[1]==0):
p.append(e[0])
print('primes generated')
s=[]
for e in p:
pr=True
w=str(e)
if all(c not in w for c in ['2','4','6','8','5','0']):
for x in (w[i:]+w[:i] for i in range(len(w))):
if int(x) not in p:
pr=False
if pr==True:
s.append(e)
print('found',e)
print(s)
It was fairly slow! (about 12s) I know, the prime generation isn't perfect but, the final bit is the slowest. I knew that this process for upto=10e6 can be done in under a second, so after some research I removed any string manipulations in favor of this function:
def rotate(n):
prev=[]
for l in range(6,0,-1):
if(n<10**l):
length=l
while(n not in prev):
prev.append(n)
n=(n // 10) + (n % 10) * 10**(length-1)
yield n
I also removed the 5,0,2,4,6,8 testing as I didn't know how to implement it. The result? It runs even slower! (over ten minutes, I guess the 5,0,2,4,6,8 testing was a good idea)
I tried using time.time() but I didn't find anything terribly inefficient (in the first code). How is it possible to improve this code? Are there any bad practices I'm currently using?
Here is some optimized code:
import math
upto = 1000000
a = [True] * upto
p = []
for n in xrange(2,upto):
if a[n]:
p.append(n)
for k in xrange(2,(upto+n-1)//n):
a[k*n] = False
print('primes generated')
s = []
p = set(p)
for e in p:
pr=True
w=str(e)
if all(c not in w for c in ['2','4','6','8','5','0']):
for x in (w[i:]+w[:i] for i in range(len(w))):
if int(x) not in p:
pr=False
break
if pr:
s.append(e)
print(s)
most important optimizations:
simplified the sieve code
converted the list of primes into a set. This makes the test x in p be logaritmic instead of linear
added a break statement when found a non prime rotation
added cleaner (but equivalent) code:
import math
upto=1000000
sieve = [True] * upto
primes = set()
for n in xrange(2,upto):
if sieve[n]:
primes.add(n)
for k in xrange(2,(upto+n-1)//n):
sieve[k*n] = False
def good(e):
w = str(e)
for c in w:
if c not in '1379':
return False
for i in xrange(1,len(w)):
x = int(w[i:]+w[:i])
if x not in primes:
return False
return True
print filter(good,primes)
You can cut down on the time required for the first test by doing a set comparison instead of doing the full iteration each time like so:
flags = set('246850')
if not set(str(e)).intersection(flags):
# etc...
Which not only scales logarithmically, but also lets you pick up another factor of two on this step. You can even speed this up further and make it a little more elegant by transitioning it over to a generator that you can then use to do the final check like so:
flags = set('246850')
primes = set(p)
easy_checks = (str(prime) for prime in primes if not set(str(prime)).intersection(flags))
Finally you can rewrite that final bit to get rid of all the appending and whatnot, which tends to be super slow like so:
test = lambda number: any((int(number[i:]+number[:i]) in primes for i in xrange(len(number))))
final = [number for number in easy_checks if test(number)]