Just to have a more readable (than the answer by @Justin) and complete (than the answer by @Sedsarq) version of the algorithm presented in the other answers, here is a version that keeps the factors in a set
and uses the fact that factors always come in pairs:
from math import sqrt
def get_factors(n):
"""Returns a sorted list of all unique factors of `n`."""
factors = set()
for i in range(1, int(sqrt(n)) + 1):
if n % i == 0:
factors.update([i, n // i])
return sorted(factors)
Compared to your code this has the added advantage that it is encapsulated in a function, so you can call it repeatedly and give it a clear name and docstring describing what the function does.
It also follows Python's official style-guide, PEP8, which programmers are encouraged to follow.
With regards to which code is fastest, I'll let this graph speak for itself:
For the op
function I used this code which has your checking of all factors up to x
:
def op(x):
factors = []
for i in range(1,x+1):
if x%i==0:
factors.append(i)
return factors
And the factors
function is from the answer by @Justin.
If all you really want is the number of factors, the best way is probably to use the prime factor decomposition. For this you can use a list of primes together with the algorithm in the answer by @Josay:
from math import sqrt
from functools import reduce
from operators import mul
def prime_sieve(limit):
prime = [True] * limit
prime[0] = prime[1] = False
for i, is_prime in enumerate(prime):
if is_prime:
yield i
for n in range(i * i, limit, i):
prime[n] = False
def prime_factors(n):
primes = prime_sieve(int(sqrt(n) + 1))
for p in primes:
c = 0
while n % p == 0:
n //= p
c += 1
if c > 0:
yield p, c
if n > 1:
yield n, 1
def prod(x):
return reduce(mul, x)
def number_of_factors(n)
return prod(c + 1 for _, c in prime_factors(n))
Comparing this with just taking the len
of the output of the get_factors
function and this function which implements your algorithm as op_count
:
def len_get_factors(n):
return len(get_factors(n))
def op_count(n):
c = 0
for i in range(1, n + 1):
if n % i == 0:
c = c + 1
return c
The following timings result (note the increased range compared to the previous plot):
x
on the order of \$10^{8}\$ is not the same as the best approach forx
on the order of \$10^{80}\$. \$\endgroup\$