You should have done Product Partitions I to do this second part.
If you solved it, you should have notice that we try to obtain the multiplicative partitions with ```n ≤ 100 ```.

In this kata we will have more challenging values, our ```n ≤  10000```. So, we need a more optimized a faster code.

We need the function ```prod_int_partII()``` that will give all the amount of different products, excepting the number itself multiplied by one.

The function ```prod_int_partII()``` will receive two arguments, the number ```n``` for the one we have to obtain all the multiplicative partitions, and an integer s that determines the products that have an amount of factors equals to ```s```.

The function will output a list with this structure:
```python
[(1), (2), [(3)]]

(1) Total amount of different products we can obtain, using the factors of n. (We do not consider the product n . 1)

(2) Total amount of products that have an amount of factors equals to s.

[(3)] A list of lists with each product represented with by a sorted list of the factors. All the product- lists should be sorted also.
If we have only one product-list as a result, the function will give only the list 
and will not use the list of lists
```
Let's see some cases:
```python
prod_int_partII(36, 3) == [8, 3, [[2, 2, 9], [2, 3, 6], [3, 3, 4]]]

/// (1) ----> 8 # Amount of different products, they are: [2, 2, 3, 3], [2, 2, 9], 
[2, 3, 6], [2, 18], [3, 3, 4], [3, 12], [4, 9], [6, 6] (8 products)
    
    (2) ----> 3 # Amount of products with three factors (see them bellow)

    (3) ----> [[2, 2, 9], [2, 3, 6], [3, 3, 4]] # These are the products with 3 factors
```
```python
prod_int_partII(48, 5) == [11, 1, [2, 2, 2, 2, 3]] # Only one list.
```
Again consider that some numbers will not have multiplicative partitions.
```python
prod_int_partII(37, 2) == [0, 0, []]
```
Happy coding!!

(Recursion is advisable)

Difficulty: introductory

Starter code:

def prod_int_partII(n, s):
	

Solutions:
def prod_int_partII(n, s, min_=2):
    total, fac = 0, []
    for d in range(min_, int(n ** .5) + 1):
        if not n % d:
            count, l, sub = prod_int_partII(n // d, s-1, d)
            if l == 1: sub = [sub]
            total += count + 1
            fac.extend([d] + x for x in sub)
    if s == 1: fac = [[n]]
    return [total, len(fac), fac[0] if len(fac) == 1 else fac]

from functools import reduce    

def updateParts(d,s,n,p):
    d.append(p)
    for t in list(s):
        s.add(tuple(sorted(t+(p,))))
        for i in range(len(t)):
            s.add( tuple(sorted(t[:i]+(p*t[i],)+(t[i+1:]))) )
    s.add((p,))
    return n//p

def prod_int_partII(n,m):
    x,d,s,p = n,[],set(),2
    while p*p<=n:
        while not n%p: n = updateParts(d,s,n,p)
        p += 1+(p!=2)
    if n-1 and n!=x: updateParts(d,s,-1,n)
    
    s = [t for t in s if reduce(int.__mul__,t)==x and len(t)>1]
    d = sorted(list(t) for t in s if len(t)==m)
    
    return [len(s),len(d),d[0] if len(d)==1 else d]

def prod_int_partII(n, s):
    part = list(mul_part_gen(n))[:-1]
    sub = [p for p in part if len(p) == s]
    return [len(part), len(sub), sub[0] if len(sub) == 1 else sub]

def mul_part_gen(n, k=2): 
    if n == 1: 
        yield [] 
    for i in range(k, n+1): 
        if n % i == 0: 
            for part in mul_part_gen(n//i, i): 
                yield [i] + part


div=lambda n:[[i,n//i] for i in range(2,int(n**.5)+1) if not n%i]
def prod_int_partII(n, s):
        li,parts = div(n), set()
        def recur(li, s=[]):
            parts.add(tuple(sorted(s)))
            for i in li:
                recur(div(i[1]),s+i if not s else s[:-1]+i)
        recur(li)
        req = sorted(filter(lambda x:len(x)==s, parts))
        return [len(parts)-1, len(req), list([map(list,req),req[0]][len(req)==1]) if req else []]

from math import sqrt

def partitions(n, floor = 2):
    parts = [[n]]
    for i in range(floor, int(sqrt(n)) + 1):
        if n % i == 0:
            for part in partitions(n // i, i):
                parts.append([i] + part) 
    return parts

def prod_int_partII(n, s):
    lists = []
    parts = partitions(n, 2)
    for part in parts:
        if len(part) == s:
            lists.append(part)
    if len(lists) == 1:
        list = lists[0]
    else:
        list = lists
    return [len(parts) - 1, len(lists), list]

def prod_int_partII(n, s):
    comb = set()
    
    for p in partition(n):
        if len(p) > 1: comb.add(tuple(sorted(p)))
    
    res = sorted([p for p in comb if len(p) == s])
    
    return [len(comb), len(res), list(res[0]) if len(res) == 1 else [list(t) for t in res]]
    
def partition(n, start = 2):
    if n == 1:
        yield []
    for i in range(start, n + 1):
        if n % i == 0:
            for p in partition(n // i, i):
                yield p + [i]

def p(n,z=2):
    r=[]
    s=0
    for i in range(z,int(n**.5)+1):
        if n%i==0:
            x,y=p(n//i,i)
            s+=x+1
            r+=[[i]+v for v in y]+[[i,n//i]]
    return s,r
def prod_int_partII(n, l): # n, integer to have the multiplicative partitions
    s,r=p(n)
    x=[v for v in r if len(v)==l]
    L=len(x)
    if L==1:x=x[0]
    return[s,L,x]


def prod_int_partII(n, s):
    res = []
    stack = [[n, 2, []]]
    while stack:
        m, d, store = stack.pop(0)
        for i in range(d, int(m**0.5) + 1):
            if m % i == 0:
                res.append(store + [i] + [m // i])
                stack.append([m // i, i, store + [i]])
    filtred_res = list(filter(lambda x: len(x) == s, res))
    if filtred_res:
        return [len(res), len(filtred_res), filtred_res] if len(filtred_res) > 1 else [len(res), len(filtred_res), filtred_res[0]]
    else:
        return [len(res), 0, []]

#!/usr/bin/env python
from collections import defaultdict
from itertools import islice

def primes():
    yield 2
    D = defaultdict(list)
    i = 3
    while True:
        if i not in D:
            D[i * i].append(i)
            yield i
        else:
            for k in D[i]:
                j = i + k
                while j % 2 == 0: j += k
                D[j].append(k)
            del D[i]
        i += 2


PRIMES = list(islice(primes(), 1000))

def decompose(n):
    r = defaultdict(int)
    for p in PRIMES:
        while n % p == 0: r[p] += 1; n //= p
        if n == 1: break
    return r


def prod_int_partII(n, s):
    r = []
    d = decompose(n)
    ds = [i for i in range(2, n) if n % i == 0]
    total = sum(i for _, i in list(d.items()))
    q = defaultdict(list)
    def aux(m, ci, c, i=0, p=[]):
        if c == 0:
            if m == 1: q[ci].append(p)
            return
        else:
            for j in range(i, len(ds)):
                if m % ds[j] == 0: aux(m // ds[j], ci, c - 1, j, p + [ds[j]])
    for i in range(2, total + 1): aux(n, i, i)
    return [sum(len(i) for i in list(q.values())), len(q[s]), q[s][0] if len(q[s]) == 1 else q[s]]