简体   繁体   中英

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]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM