Every number may be factored in prime factors.

For example, the number 18 may be factored by its prime factors ``` 2 ``` and ```3```
```
18 = 2 . 3 . 3 = 2 . 3²
```
The sum of the prime factors of 18 is  ```2 + 3 + 3 = 8```

But some numbers like 70 are divisible by the sum of its prime factors:
```
70 = 2 . 5 . 7 # sum of prime factors = 2 + 5 + 7 = 14
and 70 is a multiple of 14
```
Of course that primes would fulfill this property, but is obvious, because the prime decomposition of a number, is the number itself and every number is divisible by iself. That is why we will discard every prime number in the results

We are interested in collect the integer positive numbers (non primes) that have this property in a certain range ```[a, b]``` (inclusive).

Make the function ```mult_primefactor_sum()```, that receives the values ```a```, ```b``` as limits of the range ```[a, b]``` and ```a < b``` and outputs the sorted list of these numbers.

Let's see some cases:
```python
mult_primefactor_sum(10, 100) == [16, 27, 30, 60, 70, 72, 84] 

mult_primefactor_sum(1, 60) == [1, 4, 16, 27, 30, 60]
```

Difficulty: introductory

Starter code:

def mult_primefactor_sum(a, b):
	

Solutions:
def mult_primefactor_sum(a, b): 
    s=[]
    for i in range(a,b+1):
       r=factorize_add(i)
       if r!=i and i%r==0: s.append(i)
    return s
    
def factorize_add(num):
    if num<4: return num
    d=2; p=0
    while d<num**.5+1:
        while not num%d: p+=d; num/=d
        d+=1 if d==2 else 2
    return p if num==1 else p+num

def mult_primefactor_sum(a, b):
    ret = []
    for m in range(a, b + 1):
        p, s, n = 2, 0, m
        while n > 1 and p <= n ** .5:
            while n % p == 0:
                s += p
                n //= p
            p += 1
        s += n > 1 and n
        if s < m and m % s == 0:
            ret.append(m)
    return ret

from bisect import bisect_left, bisect_right

def spf(n):
    result = 0
    nd = 0
    while n % 2 == 0:
        result += 2
        nd += 1
        n //= 2
    d = 3
    while n > 1:
        while n % d == 0:
            result += d
            n //= d
            nd += 1
        d += 2
    return n+1 if nd == 1 else (result or n+1)  # nd == 1 -> prime

xs = [x for x in range(1, 20001) if x % spf(x) == 0]

def mult_primefactor_sum(a, b):
    i = bisect_left(xs, a)
    j = bisect_right(xs, b)
    return xs[i:j]

def mult_primefactor_sum(a, b):
    prime_factors = [factorize(n) for n in range(a, b+1)]
    return [n for n, pf in enumerate(prime_factors, a) if len(pf) > 1 and n % sum(pf) == 0]


# Memoization and this factorization algorithm are overkill here,
# one of them is enough (I didn't try none of them).
# More simple than memoize is to precompute prime_factors, if you
# know the max number to factorize (seems to be 20000 here).

def memoize(func):
    cache = {}
    def wrapper(*args):
        if args not in cache:
            cache[args] = func(*args)
        return cache[args]
    return wrapper

@memoize
def factorize(n):
    if n < 2:
        return []
    factors = []
    for k in (2, 3):
        while n % k == 0:
            n //= k
            factors.append(k)
    k = 5
    step = 2
    while k * k <= n:
        if n % k:
            k += step
            step = 6 - step
        else:
            n //= k
            factors.append(k)
    if n > 1:
        factors.append(n)
    return factors

''' keep track of numbers checked '''
NUMS = [0, 0]

def mult_primefactor_sum(a, b):
    
    ''' only check numbers greater than before '''
    for n in range(len(NUMS), b+1):
        x, div, factors = n, 2, []
        
        ''' generate prime factors '''
        while x > 1:
            if x % div == 0:
                factors.append(div)
                x //= div
            else:
                div += 1 if div == 2 else 2
        
        ''' store number if it fulfills the conditions, otherwise put 0 '''
        if len(factors) == 1 or n % sum(factors) != 0:
            NUMS.append(0)
        else:
            NUMS.append(n)
    
    ''' return the results '''
    return [ x for x in NUMS[a:b+1] if x ]

def primes(n):
    primfac = []
    d = 2
    while d*d <= n:
        while (n % d) == 0:
            primfac.append(d)
            n //= d
        d += 1
    if n > 1:
       primfac.append(n)
    return primfac
def mult_primefactor_sum(a, b): 
    l = []
    for i in range(a, b+1):
        factors = primes(i) 
        if i>sum(factors) and not i%sum(factors):
            l.append(i)
    return l

def prime_factorizations(n):
    sieve = [0 for x in range(n)]
    for i in range(2, n):
        if not sieve[i]:
            sieve[i] = i
            for r in range(i, n, i):
                sieve[r] = sieve[r] or i
    return sieve

def factor_sum(sieve, n):
    results = 0
    while n > 1:
        p = sieve[n]
        results += p
        if p == n:
            break
        n //= p
    return results

def mult_primefactor_sum(a, b):
    sieve = prime_factorizations(b+1)
    return [n for n in range(a, b+1) if sieve[n]!=n and n%factor_sum(sieve, n)==0]

def prime_factors(n):
    if n%2==0 and n>0:return [2]+prime_factors(n//2)
       
    for a in range(3,int(n**.5)+1,2):            
        if n%a==0:return sorted(prime_factors(n//a)+prime_factors(a))        
    return [n] if n>1 else []

def mult_primefactor_sum(a, b): # [a, b] range of numbers included a and b
    return [c for c in range(a,b+1) if len(prime_factors(c))>1 and c%sum(prime_factors(c))==0]