For-Else Statement with Multiple If-Break Conditions - python

I wrote a simple python module that returns the prime numbers up to a given N, using a bool flag is_prime as follows:
def generate_primes_up_to(M):
n = 2
primes = []
while n <= M:
is_prime = True
for p in primes:
if p**2 > n: break
if n % p == 0:
is_prime = False
break
if is_prime: primes.append(n)
n += 1
return primes
if __name__ == '__main__':
generate_primes_up_to(100)
which outputs:
[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]
Now, this is actually an ideal case for using the for-else construct, since the number n is prime only if no breaks occurred in the for loop. Thus, I changed the function into:
def generate_primes_up_to(M, flag='nonumpy'):
n = 2
primes = []
while n <= M:
for p in primes:
if p**2 > n: break
if n % p == 0: break
else: primes.append(n)
n += 1
return primes
but now the code outputs:
[2, 5, 27]
I don't understand why the if p**2 > n: break expression is interfering with the flow of the for-else clause. If I remove that line the code yields the right output again.

The condition causing the issue is -
if p**2 > n: break
Lets take an example - 7 , when we are checking if 7 is prime or not , we have already found out that - [2,3,5] are primes, the above condition breaks the for loop, when we check 3 as 3**2 = 9 which is greater than 7 .
Remove that condition and it works fine (Though its very slow).
In the original loop (without the for-else construct) , it worked because in that condition you just broke out of the loop, you did not change the flag is_prime .
With the for..else construct, what happens is that, the else part is only executed when we exit the loop without using break statement.
But in the case of the above condition , we use break statement and hence else part is not executed.

You can also use next:
def generate_primes_up_to(M):
n = 2
primes = []
while n <= M:
if next((False for p in primes if not n % p), True):
primes.append(n)
n += 1
return primes

Related

Is there anything wrong with syntax of "for" loop in my list comprehension?

If this is correct
v = [22, 13, 45, 50, 98, 69, 43, 44, 1]
[ (x+1 if x >=45 else x+5) for x in v ]
then what's wrong with this code?:
def isPrime(num):
is_prime = False
if num > 1:
for i in range(2, num):
if (num % i) == 0:
is_prime = False
break
else:
is_prime = True
else:
is_prime = False
return is_prime
listTablesOnlyPrimes = [[ (i*num if isPrime(i*num)==True else pass) for i in range(1, 11)] for num in range(1, 11)]
for listTable in listTablesOnlyPrimes:
print(listTable)
I want to know what's the SyntaxError in message by interpreter:
listTablesOnlyPrimes = [[ (i*num if isPrime(i*num)==True else pass) for i in range(1, 11)] for num in range(1, 11)]
^
SyntaxError: invalid syntax
This uses a conditional expression, of the form https://docs.python.org/3/reference/expressions.html#conditional-expressions
(x+1 if x >=45 else x+5)
But this does not fit that syntax because there's no else:
(i*num if isPrime(i*num)==True)
I believe that was intended to be an if condition as part of the list comprehension syntax, but that comes at the end, as described here https://docs.python.org/3/reference/expressions.html#displays-for-lists-sets-and-dictionaries
addendum:
not part of the question, but since you asked, here's a way to quickly add some unit testing to your code. Just put this right after your isPrime function
if not isPrime(11):
raise ValueError("isPrime isn't right")
You do need a few more checks, but that is enough for now. I don't want to go into the whole unit test library.
Problem is with if condition inside the nested list
listTablesOnlyPrimes = [[ (i*num) for i in range(1, 11) if isPrime(i*num)==True] for num in range(1, 11)]
Note:
Your code always return empty lists I don't understand why are you doing this i * num never become prime if i > 1

How to find prime numbers in python

I'm new to Python. I am trying to count the prime numbers in a given range. Some of the answers that developers have shared are like this:
import math
def count_primes(num):
out = []
for i in range(3,num,2):
if all(i%j!=0 for j in range(3,int(math.sqrt(i))+1,2)):
out.append(i)
print(out)
I wrote a one like this:
import math
def count_primes(num):
out = []
for i in range(3,num,2):
for j in range(3, int(math.sqrt(i))+1,2):
if i%j != 0:
out.append(i)
print(out)
but it doesn't work. Could somebody please help me. Appreciated!
Neither of your example count_primes() functions actually counts primes -- they simply print odd primes. Let's implement a working version of your trial division code, not using confusing booleans and a bad algorithm, but rather taking advantage of Python's else clause on for loops:
def collect_odd_primes(number):
primes = []
for candidate in range(3, number, 2):
for divisor in range(3, int(candidate ** 0.5) + 1, 2):
if candidate % divisor == 0:
break
else: # no break
primes.append(candidate)
return primes
print(collect_odd_primes(40))
OUTPUT
> python3 test.py
[3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37]
>
As #MarkRansom comments, the Sieve of Eratosthenes is the better way to go. (+1) Now, let's convert our code to count odd primes instead:
def count_odd_primes(number):
count = 0
for candidate in range(3, number, 2):
for divisor in range(3, int(candidate ** 0.5) + 1, 2):
if candidate % divisor == 0:
break
else: # no break
count += 1
return count
print(count_odd_primes(40))
OUTPUT
> python3 test.py
11
>
Something like this should work. You have to set a variable, because 15%9 != 0, outputs True.
import math
def count_primes(num):
out = []
for i in range(3,num,2):
prime = True
for j in range(3, int(math.sqrt(i))+1,2):
if i%j == 0:
prime = False
if prime:
out.append(i)
print(out)
count_primes(15)
The reason your code and the other is is different is because their use of the all() method. Have a look at how i implemented the method using bools:
import math
def count_primes(num):
out = []
for i in range(3,num,2):
f = True
for j in range(3,int(math.sqrt(i))+1,2):
if i%j==0:
f = False
break
if f:
out.append(i)
print(out)
count_primes(20)
Output:
[3, 5, 7, 11, 13, 17, 19]
You’re appending to the result of the module is unequal to zero. However, it’s only a prime number if all modulo are unequal to zero (there is an all statement missing in your code).
Depending on what program you're running for your code-writing, an alternative method—as opposed to the other answers to this question—would be to write:
n = int(input("Write an integer:"))
m = 2
if n == 1:
print(n, "is a prime number!")
if n == 2:
print(n, "is not a prime number.")
while n > m:
if n % m == 0:
m = m + 1
print(n, "is not a prime number.")
break
if n > n % m > 0:
m = m + 1
print(n, "is a prime number!")
break
It may not be the most efficient, but it gives you a really nice, straight answer to whether or not "x" is a prime number!

Iterate through list and find prime numbers and add to another list

I want to iterate through a list in python, detect prime numbers and then add them to another list.
primes = []
nprimes = []
for j in range(0, len(arr)):
num = arr[j] #my list with numbers to check
if num > 1:
for k in range(2, num):
if (num % k) == 0:
nprimes.append(num)
break
else:
primes.append(num)
else:
print(num, " can't be checked, because its smaller than 1")
I have the problem that numbers are always added which are not prime numbers. Also in general the code does not seem to work properly.
If num % k == 0 is false you can't say it's prime directly you have to wait the whole loop, so move the else with the for loop, it'll be executed of no break has been encountered which means it's prime
you may iterate directly on the values for num in arr
you can stop your loop at sqrt(num) you won't find a new divisor after that
for num in arr:
if num > 1:
for k in range(2, int(num ** 0.5) + 1):
if num % k == 0:
nprimes.append(num)
break
else:
primes.append(num)
else:
print(num, " can't be checked, because its smaller than 1")
For learning purposes, let's play with a different approach. First, I recommend you move your trial division code into its own predicate function is_prime(), that returns True or False, so it can be optimized independently of the rest of your code.
Then, I'm going to have itertools.groupby divide the list into prime and non-prime sequences that we splice onto the appropriate lists:
def is_prime(number):
if number < 2:
return False
if number % 2 == 0:
return number == 2
for divisor in range(3, int(number ** 0.5) + 1, 2):
if number % divisor == 0:
return False
return True
if __name__ == "__main__":
from random import sample
from itertools import groupby
array = sample(range(1, 100), 15)
primes = []
composites = []
for are_prime, numbers in groupby(array, is_prime):
if are_prime:
primes.extend(numbers)
else:
composites.extend(numbers)
print("Numbers:", array)
print("Primes:", primes)
print("Composites:", composites)
OUTPUT
% python3 test.py
Numbers: [91, 87, 10, 2, 11, 24, 21, 12, 46, 61, 15, 32, 57, 22, 5]
Primes: [2, 11, 61, 5]
Composites: [91, 87, 10, 24, 21, 12, 46, 15, 32, 57, 22]
%
There are lots of ways to go about this problem, many of them educational!

Python: Prime number algortihm implementation with square root

I am trying to solve this problem and despite wrapping my head around it I get stucked over and over and over.
I have a list made of one element [2] and given that and knowing that in order to get a prime number $N$ I have to check that it does not have any prime factor smaller or equal than $\sqrt{N}$, generate all prime numbers between 3 and 100
My code is the following and I will try to explain how I came up with it:
prime_numbers = [2]
for k in range(3,100): # k runs on all numbers to check them
for i in range (0,len(prime_numbers)): # i is the index of the elements in my list
if prime_numbers[i] <= sqrt(k): # first I need to check the sqrt condition
if k % prime_numbers[i] ==0: # check that element in list divides k
k+=1 # if so k++ and break the cicle
break
else:
i +=1 # otherwise go to the next elem of the list
else: #if the sqrt condition is not met I have found a prime number
value = k
prime_numbers.append(value)
When I run this code it gets into a loop with no exit, and I cannot individuate where the issue is. My best guess would be to correct the most indented else condition, but all the attempts I have done have resulted in failure. Thanks to everyone who is willing to partecipate.
This works:
prime_numbers = [2]
for prime_candidate in range(3, 100):
for known_prime in prime_numbers:
if known_prime <= sqrt(prime_candidate):
if prime_candidate % known_prime == 0:
break
else:
prime_numbers.append(prime_candidate)
Your problem mainly was, that i += 1 does not prevent prime_numbers.append to append again.
The for/else can be substituted by a separate flag to trigger all cases without a break happening earlier.
One way to get there is:
from math import sqrt
prime_numbers=[2]
for k in range(3,101):
prime=True
for i in range(2, int(sqrt(k))+2):
if k%i == 0:
prime=False
break
if prime:
prime_numbers.append(k)
print(prime_numbers)
#Output:
#[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]
Notes:
It's range(3,101) and not range(3,100) if assuming you want to check all numbers including 100, otherwise your last number checked will be 99.
Have a boolean variable prime; start by assuming the number is prime (prime=True)
sqrt(k) returns a float, while your range expects integers; as such - int(sqrt(k)). It's +2 to ensure your range 'to' value is never smaller than your 'from' value of 2.
if k%i == 0 (if you have a divisor) the number is not prime (prime=False) and break the for loop to move to the next k
This could be my "pythonic" by doing a list comprehension, but it may be easier for you to understand in the current format
Thanks to everyone who suggested a solution. Meanwhile I came up with one myself.
prime_numbers = [2]
for k in range(3,100):
for i in range (0,len(prime_numbers)):
if prime_numbers[i] <= sqrt(k):
if k % prime_numbers[i] ==0:
k+=1
break
else:
i +=1
else:
value = k
if(value > max(prime_numbers)):
prime_numbers.append(value)

First 100 prime numbers

I know there are a number of ways to find the first 100 prime numbers but please help me in my approach. I find the value of count to be increasing but for some reason the while loop condition doesn't apply:
count = 0
while(count <= 20):
for i in range(2, 20):
for j in range(2, i):
if i < j:
print("The number",i,"is prime")
elif i % j == 0:
break
else:
print("The number",i,"is prime")
count = count + 1
print(count)
You could use Sieve of Eratosthenes to find the first n prime numbers:
def primes_upto(limit):
prime = [True] * limit
for n in range(2, limit):
if prime[n]:
yield n # n is a prime
for c in range(n*n, limit, n):
prime[c] = False # mark composites
To get the first 100 primes:
>>> list(primes_upto(542))
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, ... ,
499, 503, 509, 521, 523, 541]
To find the first n primes, you could estimate n-th prime (to pass the upper bound as the limit) or use an infinite prime number generator and get as many numbers as you need e.g., using list(itertools.islice(gen, 100)).
This is a more simpler code. We have looped all the numbers from 0 to the number until we have printed 100 prime numbers.
n=0
i=0
while n<100:
i+=1
count=1
for j in range(2,i):
if i%j==0:
count=0
break
if count==1:
print(i,end=' ')
n+=1
If one is looking for a mix of efficiency and simple code, Numpy is worth a try. With some fancy indexing, the following code does the job of implementing the sieve of Eratosthenes.
import numpy as np
ns = np.array(range(2,N))
primes = []
last_prime=2
while last_prime:
primes.append(last_prime)
ns = ns[ns%last_prime != 0]
last_prime = ns[0] if len(ns) > 0 else None
print(primes[:100])
Then just adjust N until you do have 100 primes. A good first guess is something in the order of 100*log(100) ~ 460 (coming from the prime number theorem). This will give 88 primes. Increasing N to the value of 600, you will have enough primes.
prime_count=0
n=1
while(True):
count=0
i=2
n+=1
while(i<=n):
if(n==i):
print(n)
prime_count+=1
elif(n%i==0):
break
i+=1
if(prime_count==100):
break

Categories

Resources