2

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?

Fiery Phoenix
  • 1,156
  • 2
  • 16
  • 30
  • 1
    Just a mini-advice: when checking divisibility to test a suspect prime, you don't need to check numbers higher than ``sqrt(n)``. With that modification, the ``for`` in the ``is_prime(n)`` function would look like ``for i in range(2, int(sqrt(n))): ...`` (and you would need to ``from math import sqrt`` to get the ``sqrt()`` function available). – zegkljan Apr 26 '16 at 05:49
  • related: [What is the best algorithm for checking if a number is prime?](http://stackoverflow.com/q/1801391/4279) – jfs Apr 26 '16 at 07:41

4 Answers4

3
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.

John Zwinck
  • 239,568
  • 38
  • 324
  • 436
1

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)
Reblochon Masque
  • 35,405
  • 10
  • 55
  • 80
0

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.

LearnerEarner
  • 1,020
  • 6
  • 12
0
prime = next(filter(isprime, numbers))

See find first element in a sequence that matches a predicate.

Community
  • 1
  • 1
jfs
  • 399,953
  • 195
  • 994
  • 1,670