Getting First Prime in a List of Random Numbers - python

I was playing around with the Python shell and I have what I believe is an extremely naive implementation of a function that simply returns the first prime number in a list of 100 randomly generated numbers (whose values are between 0 and 99, inclusive). Code below:
>>> def is_prime(n):
if n < 2:
return False
elif n == 2:
return True
for i in range(2, n):
if n % i == 0:
return False
return True
>>> from random import randint
>>> numbers = []
>>> for i in range(0, 100):
numbers.append(randint(0, 99))
>>> def get_first_prime(values):
temp = []
for i in values:
if is_prime(i):
temp.append(i)
return temp[0]
>>> get_first_prime(numbers)
I want this function to strictly return only the first prime number. My implementation uses a helper list to cache all primes and then simply return the element at the first index. It works, but I'm not convinced it's a good one. I'm sure there is a more efficient way of doing this that does not require scanning through the entire list, but I can't seem to think of one yet.
What are some better alternatives?

def get_first_prime(values):
for i in values:
if is_prime(i):
return i
This way you don't keep searching once you find a prime. The function implicitly returns None if no prime is found.

Yes, you do not even need to generate a list of all the random numbers, you can test each one as they are generated, and return as soon as you've found one.
from random import randint
import math
def is_prime(n):
if n < 2:
return False
elif n == 2:
return True
for i in range(2, int(math.sqrt(n) + 1)):
if n % i == 0:
return False
return True
def get_first_prime(number):
for i in range(number + 1):
n = randint(0, 99)
if is_prime(n):
return n
get_first_prime(100)

You are right. Your code not only has more time complexity (running through all the list elements even after finding the first prime) and space complexity (temp list to hold all the primes) but also stands a risk of throwing IndexError when there are no prime numbers in the list.
So you could mend it in the following manner:
def get_first_prime(values):
for i in values:
if is_prime(i):
return i
Note that when there is no prime in the input the return statement would never get executed that means there is no explicit return; in which case Python returns None. So, if you choose to, you can return the value of your choice at the end of the function outside for loop to indicate 'not found'.
def get_first_prime(values):
for i in values:
if is_prime(i):
return i
return -1
Pythonic way of dealing with this is to raise an Exception and let the caller of the function deal with the exception.

prime = next(filter(isprime, numbers))
See find first element in a sequence that matches a predicate.

Related

Writing a procedure in python that finds primes in a list, and stores them in an empty list

I am currently having some issues doing this assignment from my class:
"Write a procedure primes_only(input_list,prime_list) that takes two lists as its parameters, an input_list of numbers and an empty list called prime_list. The procedure must examine each number in list input_list. If the number is a prime number it should add a copy of that number to the prime-list. You MUST use the functions you wrote before to do most of the work for you."
Here's what i've tried to do so far:
input_list = int(input())
prime_list = []
def primes_only(input_list,prime_list):
for x in range(2,input_list):
if(input_list%x)==0:
prime_list.append(x)
else:
print(prime_list)
def is_prime(n):
if (n==1):
return False
elif (n==2):
return True;
else:
for x in range(2,n):
if(n % x==0):
return False
return True
Will someone please help?
I do not know what's in your syllabus and what you are allowed to use and what you arent,
so I have written a very simple one.
I have described what I have done in the program using comments(statements followed by the # sign).
And I have kept the is_prime function unchanged.(Though you can do it in a much fancier way as Javier has said)
And another thing the numbers given as input must be separated by commas, and must be entered at once.
Here's the code:
def is_prime(n):
if (n==1):
return False
elif (n==2):
return True;
else:
for x in range(2,n):
if(n % x==0):
return False
return True
def primes_only(input_list, prime_list):
# Iterates over each number and checks whether the
# number is prime or not, if so then it is appended
# to the prime list
for n in input_list:
# Check if the number is prime and whether it
# has already been entered into the list.
# This checks that the same element is not appended
# twice
if is_prime(n) and prime_list.count(n) == 0:
prime_list.append(n)
# Take input from the user with numbers separated by commas
# and split the input into numbers in the form of a string
input_list = input("Enter the elments->").split(",")
# Convert the numbers from string to int
for i in range(len(input_list)):
input_list[i] = int(input_list[i])
prime_list = []
primes_only(input_list, prime_list)
print(prime_list)
Sample Input and Output:
Enter the elments->1,5,3,2,4,7,3,19
[5, 3, 2, 7, 19]
The description of the problem suggests that two things are going on at once:
Detect if a number is prime.
Copy the number to the other list.
In that case, I'd write two functions: is_prime and your primes_only.
def is_prime(n: int) -> bool:
"""Returns whether the given number is prime."""
assert n > 1, 'The number must be greater than 1'
for i in range(2, n): # Could use square root of n as the upper bound.
if n % i == 0:
return False
return True
This function should be easy enough to test manually on a REPL or, even better, create some test cases.
Then:
def primes_only(nums: Iterable[int], primes: List[int]) -> None:
for n in nums:
if is_prime(n):
primes.append(n)
A fancier version:
def primes_only(nums: Iterable[int], primes: List[int]) -> None:
primes.extend(n for n in nums if is_prime(n))
(I did not test the code)

What’s wrong with my recursion for finding primes? (Python)

I’m trying to create a program that lists all the primes below an inputted number, and I came up with the code:
def primes():
num = 20
numlist = list(range(1,num+1))
i = len(numlist)
for j in numlist[2:]:
ans = divisible(j,i)
if ans:
numlist.remove(j)
print(numlist)
def divisible(m,n):
if m!=n and m%n==0:
return True
elif n == 1:
return False
else:
divisible(m, n-1)
primes()
(I used an in-browser IDE so the num part was a proxy for the input.)
My idea was to create a separate function divisible() that when inputted two ints, m and n, would check if n divides m. I'm not sure if I was right in my recursion, but I wrote divisible(m,n-1) the idea was that it would iterate through all the integers from n downward and it would return True if any n divided m, or False if it reached 1.
In the main code, m iterated through all the numbers in a list, and n is the total number of elements in the same list. I put the print(numlist) inside the if statement as an error check. The problem I’m having is nothing is printing. The code returned literally nothing. Is there something I’ve missed in how recursion works here?
There's a lot wrong here:
You've made a common beginner's recursion error in that you have a recursive function that returns a value, but when you call it recursively, you ignore the returned value. You need to deal with it or pass it along.
It seems like this modulus is backward:
if ... and m%n==0:
Maybe it should be:
if ... and n % m == 0:
You're code doesn't appear to be calculating primes. It's looks like it's calculating relative primes to n.
You start your list of numbers at 1:
numlist = list(range(1,num+1))
But you start testing at index 2:
for j in numlist[2:]:
Which is the number 3 and you never check the divisibility of the number 2.
Even with all these fixes, I don't feel your algorithm will work.
Your divisible function doesn't return anything if it falls into else part. change it as
def divisible(m, n):
if m!=m and m%n==0:
return True
elif n==1 :
return False
else:
return divisible(m,n-1)
This should work

How can I find sum of contiguous sequences of elements in a list?

I need to write a function that given a list of integers L, it returns True if the list contains a consecutive sequence of values whose sum is n, and False otherwise.
Let's say my list is: L = [2,2,4,4,0,0,2,8] and n = 3.
The function should return False because there are not consecutive values summing up to 3.
requirement: Python's modules are not allowed
I tried with:
def consecutive(L,n):
for i in range(len(L)):
for j in range(i+1, len(L)):
if sum(L[i:j+1])==n:
return True
return False
L = [2,2,4,4,0,0,2,8]
consecutive(L,3)
This is partially working because when I set n=12, it returns True. I understand there is something to fix with slicing, but I can't find out what it is.
The main problem is simple: in this situation, the range must be len+1, otherwise it will fail in fringe cases. Working code is:
def consecutive(L, n):
for i in range(len(L)+1):
for j in range(i+1,len(L)+1):
s=sum(L[i:j])
if s == n:
print(i,j,s,'TRUE') #DEBUG: remove when done
#return True #uncomment this to reintegrate
else: print(i,j,s) #DEBUG: remove when done
return False
L = [2,2,4,4,0,0,2,-3]
consecutive(L,3)
better yet, in your example, you didn't show negative numbers. If you have no negatives, you can make the code more efficient by skipping the loop when it exceeds your search value, n:
def consecutive(L, n):
for i in range(len(L)+1):
for j in range(i+1,len(L)+1):
s=sum(L[i:j])
if s == n:
print(i,j,s,'TRUE') #DEBUG: remove when done
#return True #uncomment
elif s > n:
print(i,j,s,'too big') #DEBUG: remove when done
break
else: print(i,j,s) #DEBUG: remove when done
return False
L = [2,2,4,4,0,0,2,1]
consecutive(L,3)
The naive way would be to loop through each starting potential starting point (each index) and each window size (any number from 0 to the length of the list):
def consecutive(L, n):
for i in range(len(L)):
for window_size in range(len(L)):
if sum(L[i:i + window_size]) == n:
return True
else:
return False
Note this could easily be improved, starting with not double checking the same windows multiple times (e.g., if the list is length 3, then L[2:4] and L[2:3] would be the same thing).

Why can't I add a found prime, to a list of primes?

I'm trying to just print out the found primes. I want to add to the prime[], but I get a TypeError
line 63, in isprime
primes += n
TypeError: 'int' object is not iterable
The code:
def isprime(n):
primes = []
if n == 1:
print '1 is special'
return False
for x in range(2, n):
if n%x == 0:
print '{} equals {} x {}'.format(n, x, n // x)
return False
else:
primes += n
print (n, "is a prime number")
return True
for n in range(1, 1000):
isprime(n)
+= on a list is intended to concatenate one list to another. If you want to add a single element onto the end of the list, you can either do the straightforward:
primes.append(n)
or make a temporary list to allow the list concatenation operation to work (this approach is slower, and only trivially more concise, with greater memory churn involved; I highly recommend using .append unless you need to add more than one element at a time, in which case the += approach scales better for multielement list literals):
primes += [n]
primes is a list, so to add n, which is an int, to it, you have to use the append method. Replace primes += n with primes.append(n).

How to write more Pythonic Code

I started learning python today from the tutorial on the official site.
When reading about filter(function, sequence) i thought of making a function that returns if a number is prime to use it with the filter.
notDividedBy = [2,3,4,5,6,7,8,9]
def prime(num):
"""True if num is prime, false otherwise"""
copy = notDividedBy[:]
check = True
if num in copy:
copy.remove(num)
for x in copy:
if num % x == 0:
check = False
break
return check
The above code works in the shell.
My question is: Since i feel like although a solution, it is not the most elegant one, can anyone transform this code to something more python-like?(better structure? less lines?)
I believe it would help me for better understanding of the basics of the language.
The thing is, don't use any imports or anything, just simple staff.
Creating many many copies of lists is not a particularly efficient way of doing things. Instead use the xrange() (Python 2.x) or range() (Python 3) iterator. Here's one (naive) way you could implement a primality test:
from math import sqrt
def isPrime(n):
if n < 2: return False
if n == 2: return True
if not n % 2: return False #test if n is even
#we've already remove all the even numbers, no need to test for 2
#we only need to test up to sqrt(n), because any composite numbers can be
# factored into 2 values, at least one of which is < sqrt(n)
for i in xrange(3, int(sqrt(n)) + 1, 2):
if not n % i:
return False
return True
How about this one:
def is_prime(num):
return not any(num%i == 0 for i in xrange(2,num/2+1))
for i in xrange(10):
print i, is_prime(i)
Explanation
start with:
(num%i==0 for i in xrange(2,num/2+1))
This is a generator expression. I could have made it a list comprehension:
[num%i==0 for i in xrange(2,num/2+1)]
The list comprehension is equivalent to:
ll=[]
for i in xrange(2,num/2+1):
ll.append(num%i==0)
The difference between the generator and the list comprehension is that the generator only gives up it's elements as you iterate over it -- whereas the list comprehension calculates all the values up front. Anyway, from the above code, you can see that the expression generates a sequence of True's and False's. True if the number can be divided by i and False otherwise. If we generate a sequence of all False numbers, we know we have a prime.
The next trick is the any built in function. It basically searches through an iterable and checks if any of the values is True. As soon as it hits a True, it returns True. If it gets to the end of the iterable, it returns False. So, if the entire sequence is False (a prime number) then any will return False, otherwise it returns True. This would be perfect for a not_prime function, but our function is is_prime, so we just need to invert that result using the not operator.
The benefit of using the generator expression is that it is nice and concise, but also that it allows any to return before checking every value which means that as soon as it finds a number that divides num, it returns instead of generating all num/2 numbers.
Anyway, I hope this explanation is helpful. If not, feel free to leave a comment and I'll try to explain better.
One thing off the bat, if you are going to implement prime testing in this fashion, there's no reason to use an auxillary array
def prime(num):
"""True if num is prime, false otherwise"""
check = True
#if num in copy:
# copy.remove(num)
for x in range(2,x-1):
if num % x == 0:
check = False
break
return check
Here's a 2 liner using filter().
def prime(num):
"""True if num is prime, false otherwise"""
if num < 2:
return False
return len(filter(lambda x: num % x == 0, range(2, num))) == 0

Categories