Determine primes in given range [duplicate] - python

This question already has answers here:
Print series of prime numbers in python
(36 answers)
Closed 7 years ago.
I want to use Python to determine all prime numbers in a specified range, e.g. up to 20. I have the following code:
p = [ ]
for i in range(0, 20):
for x in range(2, i):
if i%x == 0:
break
else:
p = p + [i]
break
print p
The output is:
[3, 5, 7, 9, 11, 13, 15, 17, 19]
However, 15 and 9 are not primes. What am I missing?

The else branch is executed the moment you find a number that is not divisible by i. In this case that means any odd number is being added, as those are not divisible by 2, but all even numbers are. 9 and 15 may not be primes, but they are odd.
You should only add a number if the for loop has tested all integers in the range, not when the if test fails. You can do so by unindenting the else branch so that it matches up with the for loop.
Instead of matching with the if:
for ...:
if ...:
else:
match with the for loop:
for ...:
if ...:
else:
because then it is only executed if the for loop was not ended using a break statement, e.g. when all numbers were tested and did not manage to divide x:
for i in range(0, 20):
for x in range(2, i):
if i%x == 0:
break
else:
p = p + [i]
Note that the break can then be removed from the else suite, as by that time you are no longer in the loop.
Note that to find a prime number, you only need to test up to the square root of that number; if a x is divisible by a number i, then it'll also be divisible by all divisors of i. See Why do we check up to the square root of a prime number to determine if it is prime?
And adding a number to a list can be done with list.append() too, it is a little clearer than using the addinion operator with another list:
for i in range(20):
if i < 2:
continue # not prime numbers either
for x in range(2, int(i ** 0.5) + 1):
if i % x == 0:
# found a divisor, abort search
break
else:
p.append(i)
Demo:
>>> p = []
>>> for i in range(20):
... if i < 2:
... continue # not prime numbers either
... for x in range(2, int(i ** 0.5) + 1):
... if i % x == 0:
... # found a divisor, abort search
... break
... else:
... p.append(i)
...
>>> p
[2, 3, 5, 7, 11, 13, 17, 19]

Related

how can i check if number entered is prime and if not find its prime factors in python? [duplicate]

Two part question:
Trying to determine the largest prime factor of 600851475143, I found this program online that seems to work. The problem is, I'm having a hard time figuring out how it works exactly, though I understand the basics of what the program is doing. Also, I'd like if you could shed some light on any method you may know of finding prime factors, perhaps without testing every number, and how your method works.
Here's the code that I found online for prime factorization [NOTE: This code is incorrect. See Stefan's answer below for better code.]:
n = 600851475143
i = 2
while i * i < n:
while n % i == 0:
n = n / i
i = i + 1
print(n)
#takes about ~0.01secs
Why is that code so much faster than this code, which is just to test the speed and has no real purpose other than that?
i = 1
while i < 100:
i += 1
#takes about ~3secs
This question was the first link that popped up when I googled "python prime factorization".
As pointed out by #quangpn88, this algorithm is wrong (!) for perfect squares such as n = 4, 9, 16, ... However, #quangpn88's fix does not work either, since it will yield incorrect results if the largest prime factor occurs 3 or more times, e.g., n = 2*2*2 = 8 or n = 2*3*3*3 = 54.
I believe a correct, brute-force algorithm in Python is:
def largest_prime_factor(n):
i = 2
while i * i <= n:
if n % i:
i += 1
else:
n //= i
return n
Don't use this in performance code, but it's OK for quick tests with moderately large numbers:
In [1]: %timeit largest_prime_factor(600851475143)
1000 loops, best of 3: 388 µs per loop
If the complete prime factorization is sought, this is the brute-force algorithm:
def prime_factors(n):
i = 2
factors = []
while i * i <= n:
if n % i:
i += 1
else:
n //= i
factors.append(i)
if n > 1:
factors.append(n)
return factors
Ok. So you said you understand the basics, but you're not sure EXACTLY how it works. First of all, this is a great answer to the Project Euler question it stems from. I've done a lot of research into this problem and this is by far the simplest response.
For the purpose of explanation, I'll let n = 20. To run the real Project Euler problem, let n = 600851475143.
n = 20
i = 2
while i * i < n:
while n%i == 0:
n = n / i
i = i + 1
print (n)
This explanation uses two while loops. The biggest thing to remember about while loops is that they run until they are no longer true.
The outer loop states that while i * i isn't greater than n (because the largest prime factor will never be larger than the square root of n), add 1 to i after the inner loop runs.
The inner loop states that while i divides evenly into n, replace n with n divided by i. This loop runs continuously until it is no longer true. For n=20 and i=2, n is replaced by 10, then again by 5. Because 2 doesn't evenly divide into 5, the loop stops with n=5 and the outer loop finishes, producing i+1=3.
Finally, because 3 squared is greater than 5, the outer loop is no longer true and prints the result of n.
Thanks for posting this. I looked at the code forever before realizing how exactly it worked. Hopefully, this is what you're looking for in a response. If not, let me know and I can explain further.
It looks like people are doing the Project Euler thing where you code the solution yourself. For everyone else who wants to get work done, there's the primefac module which does very large numbers very quickly:
#!python
import primefac
import sys
n = int( sys.argv[1] )
factors = list( primefac.primefac(n) )
print '\n'.join(map(str, factors))
For prime number generation I always use the Sieve of Eratosthenes:
def primes(n):
if n<=2:
return []
sieve=[True]*(n+1)
for x in range(3,int(n**0.5)+1,2):
for y in range(3,(n//x)+1,2):
sieve[(x*y)]=False
return [2]+[i for i in range(3,n,2) if sieve[i]]
In [42]: %timeit primes(10**5)
10 loops, best of 3: 60.4 ms per loop
In [43]: %timeit primes(10**6)
1 loops, best of 3: 1.01 s per loop
You can use Miller-Rabin primality test to check whether a number is prime or not. You can find its Python implementations here.
Always use timeit module to time your code, the 2nd one takes just 15us:
def func():
n = 600851475143
i = 2
while i * i < n:
while n % i == 0:
n = n / i
i = i + 1
In [19]: %timeit func()
1000 loops, best of 3: 1.35 ms per loop
def func():
i=1
while i<100:i+=1
....:
In [21]: %timeit func()
10000 loops, best of 3: 15.3 us per loop
If you are looking for pre-written code that is well maintained, use the function sympy.ntheory.primefactors from SymPy.
It returns a sorted list of prime factors of n.
>>> from sympy.ntheory import primefactors
>>> primefactors(6008)
[2, 751]
Pass the list to max() to get the biggest prime factor: max(primefactors(6008))
In case you want the prime factors of n and also the multiplicities of each of them, use sympy.ntheory.factorint.
Given a positive integer n, factorint(n) returns a dict containing the
prime factors of n as keys and their respective multiplicities as
values.
>>> from sympy.ntheory import factorint
>>> factorint(6008) # 6008 = (2**3) * (751**1)
{2: 3, 751: 1}
The code is tested against Python 3.6.9 and SymPy 1.1.1.
"""
The prime factors of 13195 are 5, 7, 13 and 29.
What is the largest prime factor of the number 600851475143 ?
"""
from sympy import primefactors
print(primefactors(600851475143)[-1])
def find_prime_facs(n):
list_of_factors=[]
i=2
while n>1:
if n%i==0:
list_of_factors.append(i)
n=n/i
i=i-1
i+=1
return list_of_factors
Isn't largest prime factor of 27 is 3 ??
The above code might be fastest,but it fails on 27 right ?
27 = 3*3*3
The above code returns 1
As far as I know.....1 is neither prime nor composite
I think, this is the better code
def prime_factors(n):
factors=[]
d=2
while(d*d<=n):
while(n>1):
while n%d==0:
factors.append(d)
n=n/d
d+=1
return factors[-1]
Another way of doing this:
import sys
n = int(sys.argv[1])
result = []
for i in xrange(2,n):
while n % i == 0:
#print i,"|",n
n = n/i
result.append(i)
if n == 1:
break
if n > 1: result.append(n)
print result
sample output :
python test.py 68
[2, 2, 17]
The code is wrong with 100. It should check case i * i = n:
I think it should be:
while i * i <= n:
if i * i = n:
n = i
break
while n%i == 0:
n = n / i
i = i + 1
print (n)
My code:
# METHOD: PRIME FACTORS
def prime_factors(n):
'''PRIME FACTORS: generates a list of prime factors for the number given
RETURNS: number(being factored), list(prime factors), count(how many loops to find factors, for optimization)
'''
num = n #number at the end
count = 0 #optimization (to count iterations)
index = 0 #index (to test)
t = [2, 3, 5, 7] #list (to test)
f = [] #prime factors list
while t[index] ** 2 <= n:
count += 1 #increment (how many loops to find factors)
if len(t) == (index + 1):
t.append(t[-2] + 6) #extend test list (as much as needed) [2, 3, 5, 7, 11, 13...]
if n % t[index]: #if 0 does else (otherwise increments, or try next t[index])
index += 1 #increment index
else:
n = n // t[index] #drop max number we are testing... (this should drastically shorten the loops)
f.append(t[index]) #append factor to list
if n > 1:
f.append(n) #add last factor...
return num, f, f'count optimization: {count}'
Which I compared to the code with the most votes, which was very fast
def prime_factors2(n):
i = 2
factors = []
count = 0 #added to test optimization
while i * i <= n:
count += 1 #added to test optimization
if n % i:
i += 1
else:
n //= i
factors.append(i)
if n > 1:
factors.append(n)
return factors, f'count: {count}' #print with (count added)
TESTING, (note, I added a COUNT in each loop to test the optimization)
# >>> prime_factors2(600851475143)
# ([71, 839, 1471, 6857], 'count: 1472')
# >>> prime_factors(600851475143)
# (600851475143, [71, 839, 1471, 6857], 'count optimization: 494')
I figure this code could be modified easily to get the (largest factor) or whatever else is needed. I'm open to any questions, my goal is to improve this much more as well for larger primes and factors.
In case you want to use numpy here's a way to create an array of all primes not greater than n:
[ i for i in np.arange(2,n+1) if 0 not in np.array([i] * (i-2) ) % np.arange(2,i)]
Check this out, it might help you a bit in your understanding.
#program to find the prime factors of a given number
import sympy as smp
try:
number = int(input('Enter a number : '))
except(ValueError) :
print('Please enter an integer !')
num = number
prime_factors = []
if smp.isprime(number) :
prime_factors.append(number)
else :
for i in range(2, int(number/2) + 1) :
"""while figuring out prime factors of a given number, n
keep in mind that a number can itself be prime or if not,
then all its prime factors will be less than or equal to its int(n/2 + 1)"""
if smp.isprime(i) and number % i == 0 :
while(number % i == 0) :
prime_factors.append(i)
number = number / i
print('prime factors of ' + str(num) + ' - ')
for i in prime_factors :
print(i, end = ' ')
This is my python code:
it has a fast check for primes and checks from highest to lowest the prime factors.
You have to stop if no new numbers came out. (Any ideas on this?)
import math
def is_prime_v3(n):
""" Return 'true' if n is a prime number, 'False' otherwise """
if n == 1:
return False
if n > 2 and n % 2 == 0:
return False
max_divisor = math.floor(math.sqrt(n))
for d in range(3, 1 + max_divisor, 2):
if n % d == 0:
return False
return True
number = <Number>
for i in range(1,math.floor(number/2)):
if is_prime_v3(i):
if number % i == 0:
print("Found: {} with factor {}".format(number / i, i))
The answer for the initial question arrives in a fraction of a second.
Below are two ways to generate prime factors of given number efficiently:
from math import sqrt
def prime_factors(num):
'''
This function collectes all prime factors of given number and prints them.
'''
prime_factors_list = []
while num % 2 == 0:
prime_factors_list.append(2)
num /= 2
for i in range(3, int(sqrt(num))+1, 2):
if num % i == 0:
prime_factors_list.append(i)
num /= i
if num > 2:
prime_factors_list.append(int(num))
print(sorted(prime_factors_list))
val = int(input('Enter number:'))
prime_factors(val)
def prime_factors_generator(num):
'''
This function creates a generator for prime factors of given number and generates the factors until user asks for them.
It handles StopIteration if generator exhausted.
'''
while num % 2 == 0:
yield 2
num /= 2
for i in range(3, int(sqrt(num))+1, 2):
if num % i == 0:
yield i
num /= i
if num > 2:
yield int(num)
val = int(input('Enter number:'))
prime_gen = prime_factors_generator(val)
while True:
try:
print(next(prime_gen))
except StopIteration:
print('Generator exhausted...')
break
else:
flag = input('Do you want next prime factor ? "y" or "n":')
if flag == 'y':
continue
elif flag == 'n':
break
else:
print('Please try again and enter a correct choice i.e. either y or n')
Since nobody has been trying to hack this with old nice reduce method, I'm going to take this occupation. This method isn't flexible for problems like this because it performs loop of repeated actions over array of arguments and there's no way how to interrupt this loop by default. The door open after we have implemented our own interupted reduce for interrupted loops like this:
from functools import reduce
def inner_func(func, cond, x, y):
res = func(x, y)
if not cond(res):
raise StopIteration(x, y)
return res
def ireducewhile(func, cond, iterable):
# generates intermediary results of args while reducing
iterable = iter(iterable)
x = next(iterable)
yield x
for y in iterable:
try:
x = inner_func(func, cond, x, y)
except StopIteration:
break
yield x
After that we are able to use some func that is the same as an input of standard Python reduce method. Let this func be defined in a following way:
def division(c):
num, start = c
for i in range(start, int(num**0.5)+1):
if num % i == 0:
return (num//i, i)
return None
Assuming we want to factor a number 600851475143, an expected output of this function after repeated use of this function should be this:
(600851475143, 2) -> (8462696833 -> 71), (10086647 -> 839), (6857, 1471) -> None
The first item of tuple is a number that division method takes and tries to divide by the smallest divisor starting from second item and finishing with square root of this number. If no divisor exists, None is returned.
Now we need to start with iterator defined like this:
def gener(prime):
# returns and infinite generator (600851475143, 2), 0, 0, 0...
yield (prime, 2)
while True:
yield 0
Finally, the result of looping is:
result = list(ireducewhile(lambda x,y: div(x), lambda x: x is not None, iterable=gen(600851475143)))
#result: [(600851475143, 2), (8462696833, 71), (10086647, 839), (6857, 1471)]
And outputting prime divisors can be captured by:
if len(result) == 1: output = result[0][0]
else: output = list(map(lambda x: x[1], result[1:]))+[result[-1][0]]
#output: [2, 71, 839, 1471]
Note:
In order to make it more efficient, you might like to use pregenerated primes that lies in specific range instead of all the values of this range.
You shouldn't loop till the square root of the number! It may be right some times, but not always!
Largest prime factor of 10 is 5, which is bigger than the sqrt(10) (3.16, aprox).
Largest prime factor of 33 is 11, which is bigger than the sqrt(33) (5.5,74, aprox).
You're confusing this with the propriety which states that, if a number has a prime factor bigger than its sqrt, it has to have at least another one other prime factor smaller than its sqrt. So, with you want to test if a number is prime, you only need to test till its sqrt.
def prime(n):
for i in range(2,n):
if n%i==0:
return False
return True
def primefactors():
m=int(input('enter the number:'))
for i in range(2,m):
if (prime(i)):
if m%i==0:
print(i)
return print('end of it')
primefactors()
Another way that skips even numbers after 2 is handled:
def prime_factors(n):
factors = []
d = 2
step = 1
while d*d <= n:
while n>1:
while n%d == 0:
factors.append(d)
n = n/d
d += step
step = 2
return factors

Problem with Creating a Prime Factor List (Edit: Title should say 'Factor List', not 'Prime Factor List')

I'm new to Python and struggling with a coursework challenge. I need to use a loop function to list all factors of a given number (not including 1 and the number itself). Here's what I've got so far...
def factors(n):
factors = []
for i in range(2, n):
while i < n:
if n % i == 0:
factors.append(i)
return factors
print(factors(15)) # Should print [3, 5] to the console
print(factors(12)) # Should print [2, 3, 4, 6] to the console
print(factors(13)) # Should print “[]” (an empty list) to the console
By my reckoning, this should be create an empty list, then iterate through range specified by print(factors(n)), and add any prime factor to the list. However, it comes out as:
[]
[2]
[]
I though this was something to do with the iteration stopping when the function returned, so I added the while i < n:, but this doesn't seem to make a difference. In addition, I'm not allowed to edit the print(factors(n)) call at the bottom.
I'd be extremely grateful if someone could explain this to me.
Thank you in advance!
edit: changed wording 'prime factors' to 'factors'
Let's do a code review. Some of your issues are minor and some major:
(1)def factors(n):
(2) factors = []
(3) for i in range(2, n):
(4) while i < n:
(5) if n % i == 0:
(6) factors.append(i)
(7) return factors
First, in line 2 you create list named factors, which happens to be the name of your function, hiding your function definition. This would prevent your being able to recursively call your function from within your function if you needed to, which you don't in this case. But there is really no need for this. Let's call this a minor issue.
Second, all prime factors are going to be odd except for the possibility of the number 2 being a prime factor. Yet in line 3 you are testing all integers 2, 3, 4, ... n-1 to see if they are possibly prime factors when all the even numbers except for 2 cannot possibly be. The other numbers may be factors, but they are not necessarily prime. This is a major issue.
Third, given that line 3 assigns successively to i values 2 through n-1, there is no point including line 4: i has to be less than n. This is another minor issue.
Fourth, line 7 issues a return statement after having only examined the first value of i, which is 2. You have this statement at the wrong indentation level. This is another major issue.
A solution:
def prime_factors(n):
factors = []
while n >= 2 and n % 2 == 0:
factors.append(2)
n //= 2
i = 3
while i * i <= n:
if n % i == 0:
n //= i
factors.append(i)
else:
i += 2
if n > 1:
factors.append(n)
return factors
Note that this will return duplicates. That is, it will give you all the prime factors of a number so that the product of these factors yield the original number. It was not clear from your question whether this is desirable. But in your question you seem to think that the prime factors of 12 should be 2,3,4,6. They are not. They are 2,2,3.
Update
To just print factors using the corrections I pointed out:
def factors(n):
the_factors = []
for i in range(2, n):
if n % i == 0:
the_factors.append(i)
return the_factors
print(factors(15)) # Should print [3, 5] to the console
print(factors(12)) # Should print [2, 3, 4, 6] to the console
print(factors(13)) # Should print “[]” (an empty list) to the console
Prints:
[3, 5]
[2, 3, 4, 6]
[]
Since your requirement is questionable (as the earlier posts asked), so I've tried to write this solution based on the strict Prime factors definition here. You could try it and make adjustment based on the req.
def all_prime_factors(n):
''' given an positive integer - find its prime factors.
>>> all_prime_factors(12)
[2, 3]
'''
i = 2 # starting with first prime
result = []
while i * i <= n:
if n % i: # non-divisible
i += 1
else:
result.append(i) # divisible
n //= i
result.append(n) # rest n should be.
return list(set(result)) # remove duplicates
if __name__ == '__main__':
nums = [12, 13, 15, 17, 35]
for n in nums:
print(f' number {n} has -prime factors: {all_prime_factors(n)}')
The function below first creates a list of prime number smaller than n, then iterates through those numbers to extract the prime factors of n:
def factors(n):
primes = []
for i in range(2, n):
is_prime = True
for m in range(2, i):
if i % m == 0:
is_prime = False
if is_prime:
primes.append(i)
prime_factors = []
for prime in primes:
if n % prime == 0:
prime_factors.append(prime)
return prime_factors
print(factors(15))
#prints: [3, 5]

Test and return number only if divisible by a range

I am struggling to determine how to get an answer for the following problem.
What I am attempting to do is take x in a list of numbers (eg 1 to 2,000,000) and divide by a certain range of numbers, y, for example 1 to 20 and return my x value only if it is divisible by all the numbers in the second list.
I have tried the following but when I check the list I am trying to append to it returns a blank
divisibles = []
def isdivisible(x):
for i in range(1,21):
if x%i!=0:
return False
return True
for x in range(1,2000001):
if isdivisible(x):
divisibles.append(x)
Please could someone help me.
I am generally struggling with testing for an all case in general.
Thanks.
I believe this might be because no number from 1 to 2000000 is divisible by all numbers from 1 to 20.
Try calculating the LCM for those numbers first.
Your code is fine, but the result is indeed an empty list. There are several primes in range(1, 21):
2, 3, 5, 7, 11, 13, 17, 19
So, the number that will pass your check must be divisible by all of them, so it'll be at least the product of these primes:
>>> 2*3*5*7*11*13*17*19
9,699,690
You're checking up to 2 million, which isn't nearly enough.
Think that it is not possible to find a number in this range that satisfies this function because there are prime numbers such as 1,2,3,5,7 that can only be divided between them and 1. So maybe this function works, but no number fits this divisible range.
First: to check if a number is divisible by all numbers from 1 to 20 you don't need to test all dividers, it is enough to test their Least Common Multiple, which in this case is 232792560. Second: this number is greater than 2000000, so there aren't any numbers in 1 to 2000000 range satisfying your condition.
Optimized solution:
primes = []
temporary_dividor_check = []
max_nominator_divisible = []
max_div = 1
min_denominator = 1
max_denominator = 21
min_nominator = 1
max_nominator = 20000000
counter = 1
nominators = list(range(min_nominator,max_nominator+1))
denominators = range(min_denominator,max_denominator+1)
def generate_prime_numbers(start,end):
global primes
for val in range(start, end + 1):
if val > 1:
for n in range(2, val//2 + 2):
if (val % n) == 0:
break
else:
if n == val//2 + 1:
primes.append(val)
generate_prime_numbers(min_denominator,max_denominator+1)
for prime in primes:
max_div = max_div*prime
while counter * max_div < max_nominator:
max_nominator_divisible.append(counter*max_div)
counter += 1
for divisible1 in max_nominator_divisible:
if divisible1 % max_div == 0:
for denominator in denominators:
divisible = divisible % denominator
if divisible == 0:
temporary_dividor_check.append(denominator)
if temporary_dividor_check == list(denominators):
print("{} is divisible by all denominators".format(divisible1))
temporary_dividor_check = []
The simplest but super CPU-hungry (wasteful)
nominators = range(1,20000000)
denominators = range(1,21)
temporary_dividor_check = []
for nominator in nominators:
for denominator in denominators:
divisible = nominator%denominator
if divisible == 0:
temporary_dividor_check.append(denominator)
if temporary_dividor_check == list(denominators):
print("{} is divisible by all denominators".format(nominator))
temporary_dividor_check = []

Find integer with most divisor from list of integers

I am trying to write a function to find integer with most divisor from a list, but i am getting the wrong output. This is how my function looks.
def find_my_integer_divisor(mylist):
def find_divisor(k):
count =0
for i in range (1,k+1):
if k%i==0:
count +=1
return count
A=mylist[0]
for x in mylist [0:]:
A=find_divisor(x)
return A
It returns the count of the last entry in mylist. I know I have to compare the value counts from each entry and returns the integer with the most count but don't know how to do it.
This should work:
def find_divisor(k):
count =0
for i in range (1,k+1):
if k%i==0:
count +=1
return count
def find_my_integer_divisor(mylist):
return max(mylist, key=find_divisor)
Instead of actually finding all the proper factors, we can much more efficiently calculate the number possible by doing a prime factorization.
For example,
288 == 2**5 * 3**2
and the number of proper factors is
(5 + 1) * (2 + 1) - 1
^ ^ ^
number number omit one case:
of twos of threes 5 2s and 2 3s == 288,
used in used in which is not a proper
factor, factor factor of itself
0..5
(six possible
values)
To do a prime factorization, we need to start by generating primes:
def primes(known_primes=[7, 11, 13, 17, 19, 23, 29]):
"""
Generate every prime number in ascending order
"""
# 2, 3, 5 wheel
yield from (2, 3, 5)
yield from known_primes
# The first time the generator runs, known_primes
# contains all primes such that 5 < p < 2 * 3 * 5
# After each wheel cycle the list of known primes
# will be added to.
# We need to figure out where to continue from,
# which is the next multiple of 30 higher than
# the last known_prime:
base = 30 * (known_primes[-1] // 30 + 1)
new_primes = []
while True:
# offs is chosen so 30*i + offs cannot be a multiple of 2, 3, or 5
for offs in (1, 7, 11, 13, 17, 19, 23, 29):
k = base + offs # next prime candidate
for p in known_primes:
if not k % p:
# found a factor - not prime
break
elif p*p > k:
# no smaller prime factors - found a new prime
new_primes.append(k)
break
if new_primes:
yield from new_primes
known_primes.extend(new_primes)
new_primes = []
base += 30
which can be tested like
from itertools import islice
print(list(islice(primes(), 500)))
giving
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, ...
Now that we have primes, we can count the occurrences of each prime factor like so:
def prime_factor_count(n):
"""
Factorize n and yield (factor, count) for each distinct factor
"""
if n < 2:
return
else:
for p in primes():
count = 0
while not n % p:
count += 1
n //= p
if count:
yield (p, count)
if n == 1:
# number is fully factored
break
elif p*p > n:
# no smaller prime factors - remainder is prime
yield (n, 1)
break
which we can test like
print(list(prime_factor_count(288))) # => [(2, 5), (3, 2)]
which you should recognize from above, 288 == 2**5 * 3**2. Now we can
def num_proper_factors(n):
total_factors = 1
for factor, count in prime_factor_count(n):
total_factors *= (count + 1)
return total_factors - 1
which tests like
print(num_proper_factors(288)) # => 17
and finally,
def num_with_most_divisors(lst):
return max(lst, key=num_proper_factors)
QED.
short answer: use max with a key function like your's find_divisor as show by #rofls.
Long answer: in each iteration you need to compare yours previous value with the current value in your list, if the current value have a bigger count of divisor change A otherwise don't, the problem in your code is that you don't do this check. You can do something like this
def max_divisor_count(my_list):
result = my_list[0]
for n in my_list[1:]: # start in 1 because 0 is already in result
if find_divisor(n) > find_divisor(result):
result = n
return result
and this is more or less the same that the max with key-function solution does.
Of course this can be improved a little more to avoid repeat calculations like this
def max_divisor_count(my_list):
result = my_list[0]
div_count = find_divisor(result)
for n in my_list[1:]: # start in position 1 because 0 is already in result
if result != n:
temp = find_divisor(n)
if temp > div_count:
result = n
div_count = temp
return result
This is a generator expression alternative. Note I use itertools.tee to create 2 instances of the generator. The first is to calculate the max, the second to feed enumerate.
The below example also demonstrates how you can use a list comprehension to return all integers with the maximum number of divisors.
from itertools import tee
lst = [1, 2, 3, 6, 8, 10, 14]
gen1, gen2 = tee(sum(k%i==0 for i in range(1, k+1)) for k in lst)
divmax = max(gen1)
[lst[i] for i, j in enumerate(gen2) if j == divmax]
# [6, 8, 10, 14]

Python Prime Factors

Again im stuck on a problem..
I wanted to create a function that puts out all prim factors of a given number.
It was pretty much finished but it wouldnt put out correct factors for numbers which have the same prim factor more than once, for example: 20 - 5, 2, 2
So i added a while loop which checked if the product of all factors equals the number i put in.
Thanks for any help :)
prime_numbers = []
def prime_gen(upper_limit):
for i in range(2, upper_limit):
for j in range(2, i):
if i % j == 0:
break
else:
prime_numbers.append(i)
return prime_numbers
def list_product(list):
sum = 1
for i in list:
sum *= i
return sum
prime_factors = []
def prime_factor(number):
while list_product(prime_factors) != number: #without the while it checked every factor only once
for i in reversed(prime_gen(number)):
while number % i != 0:
break
else:
if i != 1:
number /= i
prime_factors.append(i)
continue
else:
break
prime_factor(20)
print (prime_factors)
Just use a for loop, getting you list of primes from prime_gen:
def prime_gen(upper_limit):
prime_numbers = [2]
for i in range(3, upper_limit,2):
for j in range(2, i):
if i % j == 0:
break
else:
prime_numbers.append(i)
return prime_numbers
def prime_factors(n):
p_f = []
for prime in prime_gen(n):
# while n is divisible keep adding the prime
while n % prime == 0:
p_f.append(prime)
# update n by dividing by the prime
n //= prime
if n > 1:
p_f.append(n)
return p_f
print(prime_factors(40))
[2, 2, 2, 5] # -> 2*2*2*5
If you take 40 as an example:
(40, 2) # first prime 2, 40 is divisible by 2
(20, 2) # 40 //= 2 == 20, 20 is divisible by 2
(10, 2) # 20 //= 2 == 10, 10 is divisible by 2
(5, 5) # 10 //=2 == 5, 5 is not evenly divisible by 2 or 3 so we get 5
If you want a fast way to generate the primes, you can use a sieve:
from math import sqrt
def sieve_of_eratosthenes(n):
primes = range(3, n + 1, 2) # primes above 2 must be odd so start at three and increase by 2
for base in xrange(len(primes)):
if primes[base] is None:
continue
if primes[base] >= sqrt(n): # stop at sqrt of n
break
for i in xrange(base + (base + 1) * primes[base], len(primes), primes[base]):
primes[i] = None
primes.insert(0,2)
sieve=filter(None, primes)
return sieve
The error you are getting (TypeError: 'float' object cannot be interpreted as an integer) is ultimately caused by this statement:
number /= i
In Python 3, the result of /= is always a float. To perform integer division (so that number remains an integer), use:
number //= i
After fixing this, you'll find that you have a logic error that causes an infinite loop.

Categories