-3

I have to create a function that calculates how much factors an integer has. For example, when I call factor(10) the function should be able to tell me it has 4 factors (1, 2, 5, 10). So where would I start off? Would do I need to put?

SeanC
  • 15,695
  • 5
  • 45
  • 66
bahaaz
  • 45
  • 1
  • 3
  • 9
  • 3
    Could you show us what have you tried so far? – Rik Poggi Mar 18 '12 at 19:35
  • I dont really have anything working but i will post anyway – bahaaz Mar 18 '12 at 19:36
  • @bahaaz: Please edit your question with the code. – Sven Marnach Mar 18 '12 at 19:36
  • 1
    If the number is not too large you can just run a for loop from 1 to X (inclusive) and check if `X % i` is 0. – adelbertc Mar 18 '12 at 19:37
  • 2
    Have you already read the [Wikipedia article on *integer factorization*](http://en.wikipedia.org/wiki/Integer_factorization)? – Gumbo Mar 18 '12 at 19:38
  • @bahaaz: It's not a problem if it doesn't work. We can help you in finiding where the error is (also post the complete traceback of your error). Can I also ask if it's homework? – Rik Poggi Mar 18 '12 at 19:40
  • The first solution here http://stackoverflow.com/questions/6800193/what-is-the-most-efficient-way-of-finding-all-the-factors-of-a-number-in-python is simply awesome – Levon Jul 09 '12 at 22:33

7 Answers7

3

The % (modulus) operator gives you the remainder of a division. If that remainder is 0, then the second multiple is a factor of the second. So just loop through all the numbers from 1 to n and check if they're factors; if so, add them to the list with append:

def factors(n):
    result = []

    for i in range(1, n + 1):
        if n % i == 0:
            result.append(i)

    return result

Here's a demo.

Or, more concisely using lambdas:

def factors(n):
    return filter(lambda i: n % i == 0, range(1, n + 1))

Here's a demo.

Ry-
  • 218,210
  • 55
  • 464
  • 476
  • 3
    You can stop at n/2 to save some time – Rich Mar 18 '12 at 19:44
  • ++ for taking the time to provide the demo. – Austin Henley Mar 18 '12 at 19:44
  • 1
    You need range(1, n+1) if you're doing this, else you'll miss n. – DSM Mar 18 '12 at 19:44
  • @Rich: I just want to keep it simple to understand :P – Ry- Mar 18 '12 at 19:47
  • @ninjagecko: All right, added a version for that too. Sorry if it's inefficient, I'm just learning Python. – Ry- Mar 18 '12 at 20:05
  • @minitech: FYI list comprehensions are preferred in Python when a lambda is not really needed: `half_factors = [i for i in xrange(2, int(sqrt) + 1) if n % i == 0]`, (also note that CamelCase is used only for classes). I think it should also be faster without summing `[1]` and `[n]`. – Rik Poggi Mar 18 '12 at 20:32
  • @RikPoggi: Yeah, I'm a JavaScript person :P You should add that. And what do you mean by not summing `[1]` and `[n]`? Those are factors of `n` unless `n = 1`. – Ry- Mar 18 '12 at 20:33
  • Actually I have deleted my previous comment. Whereas I previously said you can stop at `sqrt(n)`, this is only true for *prime* factors. (Counterexample: sqrt(100) is 10, but 20 still divides 100. However 20 is not prime, it is 10*2.) – ninjagecko Mar 18 '12 at 20:38
  • @minitech: I meant by already having `1` inside `halfFactors`. I don't know how it's optimized the "multiple" addition, but it should be more expensive to chain list that way (everything should be measured obviously). – Rik Poggi Mar 18 '12 at 20:39
  • @ninjagecko: It depends if a `list[::-1]` + floor division is faster then modulo on all the `numbers >= sqrt(n)`. – Rik Poggi Mar 18 '12 at 20:42
  • I kept the bones of the solution you've removed and made it an answer, hope you don't mind :) – Rik Poggi Mar 18 '12 at 21:07
1

I use this code. It tests up to sqrt(n), skipping all multiples of 2 and 3. Not that slow... This one returns only the prime factors, not composites.

def factorize(n1):
    if n1==0: return []
    if n1==1: return [1]
    n=n1
    b=[]
    while n % 2 ==0 : b.append(2);n/=2
    while n % 3 ==0 : b.append(3);n/=3
    i=5
    inc=2
    while i*i<=n:
     while n % i ==0 : b.append(i); n/=i
     i+=inc
     inc=6-inc
    if n<>1:b.append(n) 
    return b 

With a 16 figures integer:

>>> 
1234567890123456 [2, 2, 2, 2, 2, 2, 3, 7, 7, 301319, 435503] in  0.36825485272  seconds
>>> 
Antoni Gual Via
  • 714
  • 1
  • 6
  • 14
1

For small numbers:

def factors(n):
    return [f for f in range(1,n+1) if n%f==0]

For improved performance, if you are just interested in the number of primes, you can find the prime factorization. See the Wikipedia article to find algorithms for this. Once you have the prime factorization, notice that each number can either be included or excluded. For example 72 == 2^3 * 3^2. We can have either 0 or 1 or 2 or 3 3s, and 0 or 1 or 2 3s, for 4*3=12 possible combinations. (The factor of 1 corresponds to choices of 0 from each set of prime factors, and the number itself corresponds to maximally large choices from each set of prime factors.)

from functools import reduce  # needed in python3
from operators import *

def factors(n):
    primeFactors = prime_factorization_algorithm(n)
    # e.g. algorithm(72) == Counter({2:3, 3:2})

    return reduce(mul, (count+1 for factor,count in primeFactors.items()))
ninjagecko
  • 88,546
  • 24
  • 137
  • 145
1

I think that it might be worth it to measure the performances of a solution that does the module only on the first sqrt(n) numbers.

def factors(n):
    sqrt = int(n ** .5)
    half_factors = [i for i in range(1, sqrt + 1) if n % i == 0]
    return half_factors + [n // i for i in half_factors[n%sqrt == 0::-1]]

Quick test:

>>> factors(16)
[1, 2, 4, 8, 16]
>>> factors(20)
[1, 2, 4, 10, 20]

Note: Change range to xrange if you are in Python 2, but keep // that explicitly call the floor division.

Rik Poggi
  • 28,332
  • 6
  • 65
  • 82
0
import math
test = 3
p = [2]
#List of primes
correct = 0
limit = 100"""Set this to square root of number you are testing"""

while True:
    if test <= limit:
            if not test % p[correct - 1] == 0:
                correct = correct + 1
                if p[correct - 1] > test**0.5:
                    length = length + 1
                    correct = 0
                    p.append(test)
            else:
                test = test + 2
                correct = 0
    else:

        break
bt = int(input("Find factors of which number? "))
btt = bt
test_digit = 0
factors = []
num_factors = 1
factor_amount = 1
while True:
    if p[test_digit] < bt**0.5:
        if bt%p[test_digit] == 0:
            factors.append(p[test_digit])
            bt = bt / p[test_digit]
            factor_amount = factor_amount + 1
        else:
            test_digit = test_digit + 1
            if factor_amount > 1:
                num_factors = factor_amount * num_factors
                factor_amount = 1
    else:
        if bt > 1:
            factors.append(math.floor(bt))
            num_factors = num_factors * 2
        break
print(btt,"has",num_factors,"which are",factors)
    else:
        break

This should find what the prime factors and how many unique factors it has.

Dakota
  • 1
0
def num_divisors(num):
    factors = list(filter(lambda i: num%i == 0, range(1,int(num/2)+1)))
    return len(factors) + 1

The filter() function on its own does not produce a viewable array (it returns an iterator), hence why I used the list() funciton. We have returned len(factors) + 1 because to save execution time, we only found factors up to and equivalent to half of the original number. So we have missed out the number itself, hence we add 1.

Emma H
  • 68
  • 7
0

You only need to divide from 2 - sqrt (number) to find if it is composite. So, when you do that, whenever a number divides, you get two factors of it, say x and y such that x*y =number. Now, you can write a recursive factors function that recursively finds factors of number, x and y and finally return the set of factors without duplicates(you have to find a way to remove those).

SeattleOrBayArea
  • 2,808
  • 6
  • 26
  • 38