There are many faster prime generating algorithms, see for example:
The code example below uses the Sieve of Eratosthenes found in an answer of Eli Bendersky
Strings are immutable objects in Python, thus string concatenation using the plus operator is not very efficient especially for long strings, I assume a run time behavior of O(n2). A comparison of string concatenation methods can be found in Efficient String Concatenation in Python.
The following code uses join
with a generator. Also, it is not necessary to calculate the whole string beyond n + 5.
Links for understanding generators:
Code:
import math
# Sieve of Eratosthenes
# Code by David Eppstein, UC Irvine, 28 Feb 2002
# http://code.activestate.com/recipes/117119/
def gen_primes():
""" Generate an infinite sequence of prime numbers.
"""
# Maps composites to primes witnessing their compositeness.
# This is memory efficient, as the sieve is not "run forward"
# indefinitely, but only as long as required by the current
# number being tested.
#
D = {}
# The running integer that's checked for primeness
q = 2
while True:
if q not in D:
# q is a new prime.
# Yield it and mark its first multiple that isn't
# already marked in previous iterations
#
yield q
D[q * q] = [q]
else:
# q is composite. D[q] is the list of primes that
# divide it. Since we've reached q, we no longer
# need it in the map, but we'll mark the next
# multiples of its witnesses to prepare for larger
# numbers
#
for p in D[q]:
D.setdefault(p + q, []).append(p)
del D[q]
q += 1
def gen_primes_limited_by_total_length(length):
total = 0
for prime in gen_primes():
yield prime
total += len(str(prime))
if total > length:
return
def my_func(n):
return ''.join(
str(prime)
for prime in gen_primes_limited_by_total_length(n + 5)
)[n:n + 5]
print(my_func(0))
print(my_func(10))
print(my_func(10000))
print(my_func(1234567))
Result:
23571
19232
02192
81258
I do not know, how often, my_func
would be used. Thus, an alternative is to calculate the whole string in memory. But, the string generation can be a waste of time, if it is done for large number of primes, but only small values for n are used.
A small optimization of my_func
would be to limit the string length by not using the primes that are too small for n. It saves memory, but the run-time
is not much affected, because the generation of the primes cost most of the time.
def my_func(n):
total = 0
s = ''
for prime in gen_primes():
p = str(prime)
lp = len(p)
if lp <= n:
n -= lp
elif n > 0:
s = p[n:]
n = 0
else:
s += p
ls = len(s)
if ls >= 5:
return s[0:5]