Well, in my imagination this approach being optimal would
- only divide with (already) known primes (and not every number)
- up to the square root of the given number
import math
primes=[2]
def isprime(n): # NB! this is fragile,
s=int(math.sqrt(n)) # relies on `primes` being
for p in primes: # already fully grown
if n%p==0: # up to the sqrt(n)
return False
if p>s:
return True
maxn=19
for i in range(3,maxn+1):
if isprime(i):
primes.append(i)
print(primes)
print(sum(primes))
Then comes the uglification make it lambda
part
isprime=lambda n:all(n%p!=0 for p in primes)
works, but it misses the sqrt
magic, then
isprime=lambda n:all(n%p!=0 for p in (p for p in primes if p<=int(math.sqrt(n))))
which calculates int(math.sqrt(n))
for all known primes, but that could be a one-time parameter instead, either for a filter()
or for an innner lambda
(this latter one is shown here):
isprime=lambda n:all(n%p!=0 for p in (lambda s:(p for p in primes if p<=s))(int(math.sqrt(n))))
I still do not like the fact that it compares all primes to s, stopping in the middle may be more efficient, getting a slice with index(next(...))
can do that:
isprime=lambda n:all(n%p!=0 for p in primes[:(lambda s:primes.index(next(p for p in primes if p>s)))(int(math.sqrt(n)))])
just it remains ugly that next()
and index()
traverse a part of the list twice.
Then comes the outer loop, I would use reduce()
for that from functools
, as the accumulator of the reduction could be the actual list of primes, and then it would not be a separate variable.
Step 0 would be making it in a minimalist way, still with the variable primes
lying around, but using the terrible trick with tuples, (do,some,things,result)[3]
will do the things, and evaluate to the result
:
primes=[2]
isprime=lambda n:all(n%p!=0 for p in primes[:(lambda s:primes.index(next(p for p in primes if p>s)))(int(math.sqrt(n)))])
maxn=19
ps=functools.reduce(lambda primes,n:(primes.append(n) if isprime(n) else None,primes)[1],range(3,maxn+1),primes)
print(ps)
print(primes)
print(sum(primes)) # ps and primes are the same list actually
and then finalize the monster:
import math
import functools
plist=lambda maxn:functools.reduce(lambda primes,n:(primes.append(n) if (lambda n:all(n%p!=0 for p in primes[:(lambda s:primes.index(next(p for p in primes if p>s)))(int(math.sqrt(n)))]))(n) else None,primes)[1],range(3,maxn+1),[2])
primes=plist(19)
print(primes)
print(sum(primes))
Test: https://ideone.com/0y7dN9
Output:
[2, 3, 5, 7, 11, 13, 17, 19]
77
The takeaway message would be: lambdas can be useful, but actually you do not always have to use them.