2

Before you suggest that this question is similar to another, read P.P.S, pls.

Simillarly to this question, I am looking to find all the non-repeating combinations of a list of factors: But beeing looking for a python solution, and also having a slighty diferent premise, I decided it's worth opening a new question.

The input to the combinations function would be of the form [2,5,3,1,5,1,11,2], a list where the odd entries are the primes and the even are the number of times they are present. This number would be (2^5)*3*5*(11^2), or 58080. My goal is to print all the combinations (in this case products) of the different factors.

My try is the following (b is the list where i have the primes, and div a blank list where I put the divisors(don't mind 1 as a divisor):

n=len(b)//2
a=1
if a<=n:
    for i in range (n):
        for g in range (1,b[2*i+1]+1):
             div.append (b[2*i]**g)
    a+=1
if a<=n:
    for i in range (n):
        for o in range (i+1,n):
            for g in range(1,b[2*i+1]+1):
                for h in range(1,b[2*o+1]+1):
                    div.append ((b[2*i]**g)*(b[2*o]**h))

This adds to the list all the combinations of at most two different prime factors, but there must be a way to continue this to numbers of n different prime factors without mannualy adding more code. But the most important is that it will not generate repeated products. If there is an answer out there please redirect me to it. Thanks in advance to all.

P.S. For example, take 60. 60 will be factored by a function (not showed here) into [2, 2, 3, 1, 5, 1]. My desired output is all the divisors of 60, in order or not, like this [1,2,3,4,5,6,10,12,15,30,60] All the combinations of the products of the factors. (2,2*2,3,5,2*3,2*5,2*2*3,2*2*5,3*5,2*2*3*5 (and 1, that is added to div before or after))

P.P.S. The difference to this (another) question relies on 2 things. First, and most important, the point of this question isn't finding divisors, but combinations. Divisors is just the context for it, but I would like to know for future problems how to make such iterations. Second, like I said in the comments, even if were about divisors, finding the primes and only then combining them is more efficient (for large N) than looking for numbers until the sqrt, and the refered post revolves around that (for an example why, see in comments).

RicardoMM
  • 132
  • 8
  • Please edit the question to include an example of input and output. Your explanation is not clear enough by itself, and since your code doesn't do what you want, then we cannot determine what the correct behaviour should be just from reading it. – kaya3 Dec 10 '19 at 20:09
  • Do you know about `itertools`? You may want to look into them: https://docs.python.org/3/library/itertools.html Here's the combinations function specifically: https://docs.python.org/3/library/itertools.html#itertools.combinations – schillingt Dec 10 '19 at 20:09
  • Does this answer your question? [What is the most efficient way of finding all the factors of a number in Python?](https://stackoverflow.com/questions/6800193/what-is-the-most-efficient-way-of-finding-all-the-factors-of-a-number-in-python) – b_c Dec 10 '19 at 20:24
  • Are you trying to get a list like `[2, 2, 3, 1, 5, 1]` or are you trying to get the number from that list? – Guven Degirmenci Dec 10 '19 at 20:31
  • b_c, no I actually tried a similar approach before I tried this one. The reason I'm going with this method instead is that for very large N, is easier to find the prime factors than search (even if you divide by all the factors of two and only check the odds) the numbers until the sqrt. For example, we can write primes beyond 2 and 3 as 6n±1, and that way we only search 1/3 of the numbers untill the sqrt, instead of 1/2. There are better otimizations, but that's just an example. In the link you provided, the solutions are variations of searching 'till the sqrt. – RicardoMM Dec 10 '19 at 20:50
  • Guven Degirmenci, a list. If the input is [2,3,3,1], for example, I would like for the input to be [1,2,3,4,6,8,24] or with the order mixed. Like I mentioned, all the diferent products of the factors (2^3 and 3) – RicardoMM Dec 10 '19 at 20:52

1 Answers1

3

Your friend is itertools:

from itertools import product
from functools import reduce

def grow(factor, power):
    #returns list [1, factor, factor^2, ..., factor^power]
    array = []
    for pw in range(power+1):
        if pw != 0:
            k *= factor
        else: 
            k = 1
        array.append(k)
    return array

x = [2,2,3,1,5,1] 
prime_factors = [x[i] for i in range(0, len(x), 2)]
powers = [x[i] for i in range(1, len(x), 2)]
divisor_tree = [grow(*n) for n in zip(prime_factors, powers)]
divisor_groups = product(*divisor_tree)
# returns iterator of [(1, 1, 1), (1, 1, 5), (1, 3, 1), (1, 3, 5), (2, 1, 1), (2, 1, 5), (2, 3, 1), (2, 3, 5), (4, 1, 1), (4, 1, 5), (4, 3, 1), (4, 3, 5)]
result = [reduce(lambda x,y: x*y, n) for n in divisor_groups]
print(result)

Output:

[1, 5, 3, 15, 2, 10, 6, 30, 4, 20, 12, 60]

Now I introduce what it does:

  • Extracts prime_factors and their powers from your list
  • zip(prime_factors, powers) pairs them with each other
  • grow returns list consecutive powers as commented
  • divisor_groups is iterable of all possible selections from group of these lists, each item taken from separate list
  • reduce(lambda x,y: x*y, n) maps selected tuple of factors to a product of these factors, e.g. (2,3,5) -> 30

Edit:

You might like to implement grow in this way, less efficient but more readable:

def grow(factor, power):
    return [factor**i for i in range(power+1)]
mathfux
  • 5,759
  • 1
  • 14
  • 34