Find integer with most divisor from list of integers - python

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]

Related

Find large number in a list, where all previous numbers are also in the list

I am trying to implement a Yellowstone Integer calculation which suggests that "Every number appears exactly once: this is a permutation of the positive numbers". The formula I have implemented to derive the values is as follows:
import math
yellowstone_list = []
item_list = []
i = 0
while i <= 1000:
if i <= 3:
yellowstone_list.append(i)
else:
j = 1
inList = 1
while inList == 1:
minus_1 = math.gcd(j, yellowstone_list[i-1])
minus_2 = math.gcd(j, yellowstone_list[i-2])
if minus_1 == 1 and minus_2 > 1:
if j in yellowstone_list:
inList = 1
else:
inList = 0
j += 1
yellowstone_list.append(j - 1)
item_list.append(i)
i += 1
The issue becomes that as i increases, the time taken for the formula to determine the value of j also increases (naturally as i is increasingly further away from the start point of j).
What I would like to do is determine the largest value of j in the yellowstone_list, where all the values of 1 to j are already in the list.
As an example, in the below list, j would be 9, as all the values 0 - 9 are in the list:
yellowstone_list = [0, 1, 2, 3, 4, 9, 8, 15, 14, 5, 6, 25, 12, 35, 16, 7]
Any suggestions on how to implement this in an efficient manner?
For the "standalone" problem as stated the algorithm would be:
Sort the list.
Run a counter from 0 while in parallel traversing the list. Once the counter value is unequal to the list element, then you have found one-past the wanted element.
Something like the following:
x=[0, 1, 2, 3, 4, 9, 8, 15, 14, 5, 6, 25, 12, 35, 16, 7]
y=sorted(x)
for i in range(1, len(y)):
if y[i]!=i:
print(i-1)
break
But in your case it appears that the initial list is being built gradually. So each time a number is added to the list, it can be inserted in a sorted manner and can be checked against the previous element and the traversal can start from there for more efficient process.
This is how I would do it:
lst.sort()
for c, i in enumerate(lst):
if c + 1 < len(lst) and lst[c + 1] != i + 1:
j = i
break
else:
j = i
Basically, the list is sorted, and then, it loops through each value, checking if the next value is only 1 greater than the current.
After some time to sit down and think about it, and using the suggestions to sort the list, I came up with two solutions:
Sorting
I implemented #eugebe Sh.'s solution within the while i < 1000 loop as follows:
while i <= 1000:
m = sorted(yellowstone_list)
for n in range(1, len(m)):
if m[n]!=n:
break
if i == 0:
....
In List
I ran an increment to check if the value was in the list using the "in" function, also within the while i < 1000 loop, as follows:
while i <= 1000:
while k in yellowstone_list:
k += 1
if i == 0:
....
Running both codes 100 times, I got the following:
Sorting: Total: 1:56.403527 seconds, Average: 1.164035 seconds.
In List: Total: 1:14.225230 seconds, Average: 0.742252 seconds.

Project Euler #23 - Non Abundant Sums

This is the task:
Problem 23
A perfect number is a number for which the sum of its proper divisors is exactly equal to the number. For example, the sum of the proper divisors of 28 would be 1 + 2 + 4 + 7 + 14 = 28, which means that 28 is a perfect number.
A number n is called deficient if the sum of its proper divisors is less than n and it is called abundant if this sum exceeds n.
As 12 is the smallest abundant number, 1 + 2 + 3 + 4 + 6 = 16, the smallest number that can be written as the sum of two abundant numbers is 24. By mathematical analysis, it can be shown that all integers greater than 28123 can be written as the sum of two abundant numbers. However, this upper limit cannot be reduced any further by analysis >even though it is known that the greatest number that cannot be expressed as the sum of two abundant numbers is less than this limit.
Find the sum of all the positive integers which cannot be written as the sum of two abundant numbers.
This is my code:
import time
import math
start = time.time()
abundant_num_list = []
def checkAbundant():
for n in range(1, 28123):
factor_sum = 0
other_pair_factor = 0
for i in range(2, int(n ** 0.5) + 1):
if n % i == 0:
if math.floor(math.sqrt(n)) == math.sqrt(n):
other_pair_factor = 0
else:
other_pair_factor = n // i
factor_sum += (i + other_pair_factor + 1)
if n < factor_sum :
abundant_num_list.append(n)
def NonAbundantSums():
abundant_sum_list = []
all_num_list = []
non_abun_list = []
non_abun_sum = 0
for i in range(len(abundant_num_list)):
for j in range(i, len(abundant_num_list)):
if abundant_num_list[i] + abundant_num_list[j] <= 28123:
abundant_sum_list.append(abundant_num_list[i] + abundant_num_list[j])
for i in range(1, 28124):
all_num_list.append(i)
non_abun_list = [int(a) for a in (set(all_num_list) - set(abundant_sum_list))]
for i in range(len(non_abun_list)):
non_abun_sum += non_abun_list[i]
print(non_abun_sum)
checkAbundant()
NonAbundantSums()
end = time.time() - start
print("Done in", end, "seconds")
If it looks inefficient, i know, I'm new to coding. Python is my first programming language. I noticed a weird problem for my non_abun_list, where when retrieving the difference for set(all_num_list) and set(abundant_sum_list), the first and second index of abundant_sum_list is 2 and 30, so in my mind, non_abun_list shoud look like
[1, 2, 3, 4... ,22, 23, 25, 26, 27, 28, 29, 31, 32]
instead i got this
[1, 2, 3, 4... ,22, 23, 8209 ,25, 26, 27, 28, 29, 8219, 31, 32]
and i don't know how I got this list instead.
Can someone explain to me what's wrong with my code?
My result is 4352518 in ~25 seconds
Answer is 4179871
This is not an answer
(OP cannot participate in chat due to rep requirement)
You should consider your coding style. If you write concise functions to perform a task and have those functions return a value(s) then you can easily test those functions to see if they work. This makes it easier to determine what IS working.
For example when checking for abundancy you have to do two things: find the divisors of a number and compare their sum to that number.
def divisors(n):
'''return divisors of n'''
d = [1]
for i in range(2, int(pow(n,.5))+1):
if (n % i) == 0:
other = n // i
if other == i:
pair = [i]
else:
pair = [i,other]
d.extend(pair)
return d
def check(n):
'''return True if abundant'''
return sum(divisors(n)) > n
Now you can easily test both functions against known inputs and outputs if you start having problems. Once you know they work you don't have to consider them as a source of errors.
usage:
abundant_numbers = []
for n in range(12,28124):
if check(n):
abundant_numbers.append(n)
Test a couple of numbers:
>>> divisors(16)
[1, 2, 8, 4]
>>> divisors(1056)
[1, 2, 528, 3, 352, 4, 264, 6, 176, 8, 132, 11, 96, 12, 88, 16, 66, 22, 48, 24, 44, 32, 33]
>>> check(16)
False
>>> check(1056)
True
>>>
Yep, that looks right :).
for i in range(2, int(n ** 0.5) + 1):
if n % i == 0:
if math.floor(math.sqrt(n)) == math.sqrt(n) == i:
other_pair_factor = 0
else:
other_pair_factor = n // i
factor_sum += (i + other_pair_factor)
factor_sum += 1
For this specific part of checkAbundant(), i should include "== i " at line 3 because I only want the factor that will repeat twice to only count once for square numbers
For example, the pair factor as I would like to call for 36 is 1 x 36, 2 x 18, 3, 12, 4 x 9, 6 x 6.
For efficiency, I only find the first half of the factor pair, the other half is obtained through n // i. So in order to have the sum of proper factors of a number, I can't have repeated factors.
Without adding " ==i " I have made it so that for any square abundant numbers, their other half of the factor is not accounted for when summing the total factors up.
Another mistake i fixed in checkAbundant() is in line 8, where factor_sum += (i + other_pair_factor + 1)
This resulted in for every loop, factor_sum would have an additional 1, which will ruin the result. To fix that, i added 1 after the for loop
Overall, I would say it was a pretty rookie mistake. >.<

Automatically generate list from math function?

My idea is to run the 3n + 1 process (Collatz conjecture) on numbers ending in 1, 3, 7, and 9, within any arbitrary range, and to tell the code to send the lengths of each action to a list, so I can run functions on that list separately.
What I have so far is to specify unit digits 1,3,7 and 9 as: if n % 10 == 1; if n % 10 == 3 ...etc, and I think my plan needs some form of nested for loops; where I'm at with list appending is to have temp = [] and leng = [] and find a way for the code to automatically temp.clear() before each input to leng. I'm assuming there's different ways to do this, and I'm open to any ideas.
leng = []
temp = []
def col(n):
while n != 1:
print(n)
temp.append(n)
if n % 2 == 0:
n = n // 2
else:
n = n * 3 + 1
temp.append(n)
print(n)
It's unclear what specifically you're asking about and want to know, so this is only a guess. Since you only want to know the lengths of the sequences, there's no need to actually save the numbers in each one—which means there's only one list created.
def collatz(n):
""" Return length of Collatz sequence beginning with positive integer "n".
"""
count = 0
while n != 1:
n = n // 2 if n % 2 == 0 else n*3 + 1
count += 1
return count
def process_range(start, stop):
""" Return list of results of calling the collatz function to the all the
numbers in the closed interval [start...stop] that end with a digit
in the set {1, 3, 7, or 9}.
"""
return [collatz(n) for n in range(start, stop+1) if n % 10 in {1, 3, 7, 9}]
print(process_range(1, 42))
Output:
[0, 7, 16, 19, 14, 9, 12, 20, 7, 15, 111, 18, 106, 26, 21, 34, 109]

Store the result of a function as a variable

I'm trying to write an RSA code, but I'm having issues with a simple thing. I want to store the result of a function as a variable, twice in Python. This is my code
def random_odd_between(j,k):
k1 = (k-1)//2
j1 = j//2
a1 = int(random()*(k1-j1+1))+j1
a = 2*a1 +1
return a
# The list of primes less than 10^6 is given by:
list_of_primes = prime_range(1,10^6)
# Write a function to check if given number is prime:
def check_if_prime(n):
prime_flag = 1
for i in list_of_primes:
checker = n%i
if checker != 0:
if (n/i) in ZZ:
prime_flag = 0
break
else:
prime_flag = 0
break
return prime_flag
# Generate random numbers between 6*10^9 and 10^10 until we get a prime.
# Generate two prime numbers between 6*10^9 and 10^10 for p and q
def get_a_prime():
count = 0
prime_found = 0
while prime_found == 0:
a = random_odd_between(6*10^9,10^10)
prime_found = check_if_prime(a)
count = count + 1
# Print a prime you've got:
print '%i' %a
p = get_a_prime()
q = get_a_prime()
n = p*q
# Let t stand for totient
t = (p-1)*(q-1)
I can't get my p and q to be defined however, they keep just giving me an error. I realize I need to do some kind of return, but I can't get the syntax right
just replace print '%i' %a with return a
I believe you had errors in both your check_if_prime and get_a_prime functions. In the former, ZZ is not defined and the first break should be indented one more level and the last one is redundant. Better yet, just return True or False when needed.
In the second function, you need to return the value that is prime rather than just print it.
def check_if_prime(n):
if n == 2:
return True # 2 is a prime.
if n % 2 == 0 or n <= 1:
return False # Anything less than or equal to one is not prime.
for divisor in xrange(3, int(n ** 0.5) + 1, 2): # 3, 5, 7, ..., int(SQRT(n)) + 1
if not n % divisor:
return False # NOT divisible by the divisor.
return True # Must be prime.
def get_a_prime():
prime_found = False
while not prime_found:
a = random_odd_between(6 * 10 ^ 9, 10 ^ 10)
prime_found = check_if_prime(a)
return a
Testing
primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101]
# Ensure all primes above are prime per our function.
>>> all(check_if_prime(n) for n in primes)
True
# Ensure all numbers in range 0-101 that is not identified as a prime is not a prime.
>>> any(check_if_prime(n) for n in xrange(102) if n not in primes)
False

Determine primes in given range [duplicate]

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]

Categories