finding divisors of N using a list comprehension - python

I have started to write some Python code. What I have is:
from math import *
def ex(N):
l = []
sum = 0
N = abs(int(N));
for n in range(1,N):
if N % n == 0:
l.append(n)
sum += n
l.append(N)
print ' of '+str(N),l
print 'SUM', (sum+N)
I don't know if this is good or bad, but it is what I have tried :)
Is it possible to replicate the behavior of my code with list comprehension? If so, how?

l = [n for n in range(1,N+1) if N % n == 0]
total = sum(l)

Very simply (this actually uses a generator expression rather than a list comprehension, if you don't need to keep the results).
def ex(N):
N = abs(int(N))
print 'SUM', sum(n for n in xrange(1, N + 1) if N % n == 0)
If you care about the list, then instead:
def ex2(N):
N = abs(int(N))
l = [n for n in xrange(1, N + 1) if N % n == 0]
print ' of '+str(N),l
print 'SUM', sum(l)
You might find the Dive Into Python 3 explanation of list comprehensions useful, or if you've got some free hours, try watching an introductory Python tutorial.

You can do it with list-comprehension:
def ex(N):
N = abs(int(N))
l = [n for n in range(1, N + 1) if N % n == 0]
print ' of '+str(N),l
print sum(l)
You will keep the n for each n in the range from 1 to N(inclusive) if the condition(N % n == 0) is true. You will keep the list in l and then the function sum calculates the sum of the list.
Whether it is good or bad using list comprehension is up to you, but it is usually used as it is efficient and compact. And if you don't need a list because you just need to use the values one after the other and only one time generators are recommended because they don't use memory.

You can use list comprehension to replace:
for n in range(1,N):
if N % n == 0:
l.append(n)
with:
[l.append(n) for n in range(1,N) if N % n == 0]
Whether it is good or bad, in this case, I'm not sure. I like to use them when I can, but for more complex cases sometimes I opt for the for loop for readability.
Edit: Sorry, maybe I should have given a complete example.
def ex(N):
l = []
N = abs(int(N));
[l.append(n) for n in range(1,N) if N % n == 0]
l.append(N)
print l
print sum(l)

Related

Prime factorization using list comprehension in Python

How to write a function which returns a list of tuples like (c_i, k_i) for n such that n = c1^k1 * c2^k2 * ... , ci is a prime number.
For example: 12600 = 2^3 * 3^2 * 5^2 * 7^1
Desired output: [(2, 3), (3, 2), (5, 2), (7, 1)]
I know how to do it with while but is it possible to do it using list comprehension? Efficiency is not required in this task.
# naive function
def is_prime(n):
return n > 1 and all(n % i != 0 for i in range(2, n))
# while version
def factorization_while(n):
res = []
for i in range(1, n + 1):
if is_prime(i):
j = 0
while n % i == 0:
n = n // i
j += 1
if j != 0:
res.append((i, j))
return res
# list comprehension version
def factorization(n):
return [
(i, j) for i in range(1, n + 1) if is_prime(i) \
and n % i == 0 ... # add smth
]
I don't think this should be too hard. You don't actually need to modify n to find its prime factors, they're all completely independent of each other. So just iterate through the appropriate primes, and find the maximum power that works!
from math import log
def prime_factors(n):
return [(prime, max(power for power in range(1, int(log(n, prime))+1)
if n % prime**power == 0))
for prime in range(2, n+1) if n % prime == 0 and isprime(prime)]
There are a few ways you might improve this further. You could use itertools.takewhile on an infinite generator of powers (e.g. itertools.count), as once you find the first power such that prime**power is not a factor of n, none of the later ones will be either. That would allow you to avoid the log call.
And there are a whole bunch of ways to efficiently iterate over the primes (see for instance, the very simple generator suggested here, or higher performance versions that you can find in the answers to a few different questions here on SO).

Optimizing a python Code

I'm trying to optimize this code (Given two integers m, n (1 <= m <= n) we want to find all integers between m and n whose sum of squared divisors is itself a square). I'm new to coding and I'm having a hard time with this concept
def list_squared(m, n):
# your code
import math
MyList = []
for i in range(m,n):
A=[]
for k in range(1,i+1):
if i%k == 0:
A.append(k**2)
if round(math.sqrt(sum(A))) == math.sqrt(sum(A)):
B =[]
B.append(i)
B.append(sum(A))
MyList.append(B)
return MyList
import math
def list_squared(m, n):
MyList = []
for i in range(m,n):
res=0
for k in range(1,i+1):
if i%k == 0:
res+=k**2
if res == int(math.sqrt(res))**2
MyList.append(i)
return MyList
First thing that i note you can optimize is range(1,i+1). You can set initially res=1 and start the range from 2 avoiding the first cycle. The important optimization is in the end: you can stop after i/2 because there are not integer divisors after it but remember to include the dispair case (for example 3/2 = 1.5 is not a valid input for range) so wrap the result of division around ceil function. In conclusion a simple optimization is range(2, ceil(i/2)+1) with res=1

Python: What is wrong with the indexing logic in my code?

"You are given an array of n integers and an integer k. Find and print the number of (i,j) pairs where i<j and a[i] + a[j] is evenly divisible by k."
Sample input would be:
6 3
1 3 2 6 1 2
where 6 is n, 3 is k and the second line is the array of integers. The output for this input would be 5.
Here is my code, but i am not passing the test cases and am almost positive it has to do with how i am indexing it.
import sys
n,k = input().strip().split(' ')
n,k = [int(n),int(k)]
a = [int(a_temp) for a_temp in input().strip().split(' ')]
count=0;
for i in range(n):
curr = n-i
for j in range(curr):
if i < i + j:
if k % (a[i] + a[i+j]) ==0:
count = count + 1
print(count)
Also, followup question: Is this method i am approaching an efficient way of going about it?
you can try this ...
import sys
n,k = input().strip().split(' ')
n,k = [int(n),int(k)]
a = [int(a_temp) for a_temp in input().strip().split(' ')]
print(sum([1 for i in range(n) for j in range(i) if (a[i]+a[j])%k==0]))
k % ... means "k is divisible by ...", not "... is divisible by k".
if i < i + j is not very useful; you're better off doing what furas recommends in comments.
What you need is to make use of itertools.combinations:
from itertools import combinations
count = 0
for i, j in combinations(range(n), 2):
if i < j and (a[i] + a[j]) % k == 0:
print i, j
count += 1
Discussion
range(n) returns a list of indices 0 .. n-1
combinations(range(n), 2) will yield a list of two indices (without duplications)
(a[i] + a[j]) % k == 0 is the test that your asked
Note that combinations will yield pairs of i, j where i is always less than j, but the test i < j is there as a paranoid measure

Prime factorization - list

I am trying to implement a function primeFac() that takes as input a positive integer n and returns a list containing all the numbers in the prime factorization of n.
I have gotten this far but I think it would be better to use recursion here, not sure how to create a recursive code here, what would be the base case? to start with.
My code:
def primes(n):
primfac = []
d = 2
while (n > 1):
if n%d==0:
primfac.append(d)
# how do I continue from here... ?
A simple trial division:
def primes(n):
primfac = []
d = 2
while d*d <= n:
while (n % d) == 0:
primfac.append(d) # supposing you want multiple factors repeated
n //= d
d += 1
if n > 1:
primfac.append(n)
return primfac
with O(sqrt(n)) complexity (worst case). You can easily improve it by special-casing 2 and looping only over odd d (or special-casing more small primes and looping over fewer possible divisors).
The primefac module does factorizations with all the fancy techniques mathematicians have developed over the centuries:
#!python
import primefac
import sys
n = int( sys.argv[1] )
factors = list( primefac.primefac(n) )
print '\n'.join(map(str, factors))
This is a comprehension based solution, it might be the closest you can get to a recursive solution in Python while being possible to use for large numbers.
You can get proper divisors with one line:
divisors = [ d for d in xrange(2,int(math.sqrt(n))) if n % d == 0 ]
then we can test for a number in divisors to be prime:
def isprime(d): return all( d % od != 0 for od in divisors if od != d )
which tests that no other divisors divides d.
Then we can filter prime divisors:
prime_divisors = [ d for d in divisors if isprime(d) ]
Of course, it can be combined in a single function:
def primes(n):
divisors = [ d for d in range(2,n//2+1) if n % d == 0 ]
return [ d for d in divisors if \
all( d % od != 0 for od in divisors if od != d ) ]
Here, the \ is there to break the line without messing with Python indentation.
I've tweaked #user448810's answer to use iterators from itertools (and python3.4, but it should be back-portable). The solution is about 15% faster.
import itertools
def factors(n):
f = 2
increments = itertools.chain([1,2,2], itertools.cycle([4,2,4,2,4,6,2,6]))
for incr in increments:
if f*f > n:
break
while n % f == 0:
yield f
n //= f
f += incr
if n > 1:
yield n
Note that this returns an iterable, not a list. Wrap it in list() if that's what you want.
Most of the above solutions appear somewhat incomplete. A prime factorization would repeat each prime factor of the number (e.g. 9 = [3 3]).
Also, the above solutions could be written as lazy functions for implementation convenience.
The use sieve Of Eratosthenes to find primes to test is optimal, but; the above implementation used more memory than necessary.
I'm not certain if/how "wheel factorization" would be superior to applying only prime factors, for division tests of n.
While these solution are indeed helpful, I'd suggest the following two functions -
Function-1 :
def primes(n):
if n < 2: return
yield 2
plist = [2]
for i in range(3,n):
test = True
for j in plist:
if j>n**0.5:
break
if i%j==0:
test = False
break
if test:
plist.append(i)
yield i
Function-2 :
def pfactors(n):
for p in primes(n):
while n%p==0:
yield p
n=n//p
if n==1: return
list(pfactors(99999))
[3, 3, 41, 271]
3*3*41*271
99999
list(pfactors(13290059))
[3119, 4261]
3119*4261
13290059
Here is my version of factorization by trial division, which incorporates the optimization of dividing only by two and the odd integers proposed by Daniel Fischer:
def factors(n):
f, fs = 3, []
while n % 2 == 0:
fs.append(2)
n /= 2
while f * f <= n:
while n % f == 0:
fs.append(f)
n /= f
f += 2
if n > 1: fs.append(n)
return fs
An improvement on trial division by two and the odd numbers is wheel factorization, which uses a cyclic set of gaps between potential primes to greatly reduce the number of trial divisions. Here we use a 2,3,5-wheel:
def factors(n):
gaps = [1,2,2,4,2,4,2,4,6,2,6]
length, cycle = 11, 3
f, fs, nxt = 2, [], 0
while f * f <= n:
while n % f == 0:
fs.append(f)
n /= f
f += gaps[nxt]
nxt += 1
if nxt == length:
nxt = cycle
if n > 1: fs.append(n)
return fs
Thus, print factors(13290059) will output [3119, 4261]. Factoring wheels have the same O(sqrt(n)) time complexity as normal trial division, but will be two or three times faster in practice.
I've done a lot of work with prime numbers at my blog. Please feel free to visit and study.
def get_prime_factors(number):
"""
Return prime factor list for a given number
number - an integer number
Example: get_prime_factors(8) --> [2, 2, 2].
"""
if number == 1:
return []
# We have to begin with 2 instead of 1 or 0
# to avoid the calls infinite or the division by 0
for i in xrange(2, number):
# Get remainder and quotient
rd, qt = divmod(number, i)
if not qt: # if equal to zero
return [i] + get_prime_factors(rd)
return [number]
Most of the answer are making things too complex. We can do this
def prime_factors(n):
num = []
#add 2 to list or prime factors and remove all even numbers(like sieve of ertosthenes)
while(n%2 == 0):
num.append(2)
n /= 2
#divide by odd numbers and remove all of their multiples increment by 2 if no perfectlly devides add it
for i in xrange(3, int(sqrt(n))+1, 2):
while (n%i == 0):
num.append(i)
n /= i
#if no is > 2 i.e no is a prime number that is only divisible by itself add it
if n>2:
num.append(n)
print (num)
Algorithm from GeeksforGeeks
prime factors of a number:
def primefactors(x):
factorlist=[]
loop=2
while loop<=x:
if x%loop==0:
x//=loop
factorlist.append(loop)
else:
loop+=1
return factorlist
x = int(input())
alist=primefactors(x)
print(alist)
You'll get the list.
If you want to get the pairs of prime factors of a number try this:
http://pythonplanet.blogspot.in/2015/09/list-of-all-unique-pairs-of-prime.html
def factorize(n):
for f in range(2,n//2+1):
while n%f == 0:
n //= f
yield f
It's slow but dead simple. If you want to create a command-line utility, you could do:
import sys
[print(i) for i in factorize(int(sys.argv[1]))]
Here is an efficient way to accomplish what you need:
def prime_factors(n):
l = []
if n < 2: return l
if n&1==0:
l.append(2)
while n&1==0: n>>=1
i = 3
m = int(math.sqrt(n))+1
while i < m:
if n%i==0:
l.append(i)
while n%i==0: n//=i
i+= 2
m = int(math.sqrt(n))+1
if n>2: l.append(n)
return l
prime_factors(198765430488765430290) = [2, 3, 5, 7, 11, 13, 19, 23, 3607, 3803, 52579]
You can use sieve Of Eratosthenes to generate all the primes up to (n/2) + 1 and then use a list comprehension to get all the prime factors:
def rwh_primes2(n):
# http://stackoverflow.com/questions/2068372/fastest-way-to-list-all-primes-below-n-in-python/3035188#3035188
""" Input n>=6, Returns a list of primes, 2 <= p < n """
correction = (n%6>1)
n = {0:n,1:n-1,2:n+4,3:n+3,4:n+2,5:n+1}[n%6]
sieve = [True] * (n/3)
sieve[0] = False
for i in xrange(int(n**0.5)/3+1):
if sieve[i]:
k=3*i+1|1
sieve[ ((k*k)/3) ::2*k]=[False]*((n/6-(k*k)/6-1)/k+1)
sieve[(k*k+4*k-2*k*(i&1))/3::2*k]=[False]*((n/6-(k*k+4*k-2*k*(i&1))/6-1)/k+1)
return [2,3] + [3*i+1|1 for i in xrange(1,n/3-correction) if sieve[i]]
def primeFacs(n):
primes = rwh_primes2((n/2)+1)
return [x for x in primes if n%x == 0]
print primeFacs(99999)
#[3, 41, 271]
from sets import Set
# this function generates all the possible factors of a required number x
def factors_mult(X):
L = []
[L.append(i) for i in range(2,X) if X % i == 0]
return L
# this function generates list containing prime numbers upto the required number x
def prime_range(X):
l = [2]
for i in range(3,X+1):
for j in range(2,i):
if i % j == 0:
break
else:
l.append(i)
return l
# This function computes the intersection of the two lists by invoking Set from the sets module
def prime_factors(X):
y = Set(prime_range(X))
z = Set(factors_mult(X))
k = list(y & z)
k = sorted(k)
print "The prime factors of " + str(X) + " is ", k
# for eg
prime_factors(356)
Simple way to get the desired solution
def Factor(n):
d = 2
factors = []
while n >= d*d:
if n % d == 0:
n//=d
# print(d,end = " ")
factors.append(d)
else:
d = d+1
if n>1:
# print(int(n))
factors.append(n)
return factors
This is the code I made. It works fine for numbers with small primes, but it takes a while for numbers with primes in the millions.
def pfactor(num):
div = 2
pflist = []
while div <= num:
if num % div == 0:
pflist.append(div)
num /= div
else:
div += 1
# The stuff afterwards is just to convert the list of primes into an expression
pfex = ''
for item in list(set(pflist)):
pfex += str(item) + '^' + str(pflist.count(item)) + ' * '
pfex = pfex[0:-3]
return pfex
I would like to share my code for finding the prime factors of number given input by the user:
a = int(input("Enter a number: "))
def prime(a):
b = list()
i = 1
while i<=a:
if a%i ==0 and i!=1 and i!=a:
b.append(i)
i+=1
return b
c = list()
for x in prime(a):
if len(prime(x)) == 0:
c.append(x)
print(c)
def prime_factors(num, dd=2):
while dd <= num and num>1:
if num % dd == 0:
num //= dd
yield dd
dd +=1
Lot of answers above fail on small primes, e.g. 3, 5 and 7. The above is succinct and fast enough for ordinary use.
print list(prime_factors(3))
[3]

did my program on perfect numbers in python and not sure if i should use (1,1000) or (2, n+1) in range

I did lab on perfect numbers in python it runs fine and prints numbers that I need. But not sure if I need to put (1, 1000) in range or (2, n+1) is fine? My instruction asking me to
"Write a python program to find all the perfect numbers from 1 to 10,000. When a perfect number is found, your logic should print it."
What is a perfect number:
In number theory, a perfect number is a positive integer that is equal to the sum of its proper positive divisors, that is, the sum of its positive divisors excluding the number itself (also known as its aliquot sum). Equivalently, a perfect number is a number that is half the sum of all of its positive divisors (including itself) i.e. σ1(n) = 2n.
When I run my program it prints out 6, 28, 496, and 8128.
n = 1
while True:
factors = [1]
[factors.append(i) for i in range(2,n+1) if n%i == 0]
if sum(factors) == 2*n: print n
n += 1
something like:
you can also use a range(1,n) as perfect number is equal to sum of all its divisors except itself, i.e. 6=1+2+3
n = 1
while True:
factors =(i for i in range(1,n) if n%i == 0) #use a generator expression
if sum(factors) == n:
print n
n += 1
output:
6
28
496
8128
or a one liner:
In [2]: [x for x in xrange(1,10001) if sum(y for y in xrange(1,x) if x%y==0)==x]
Out[2]: [6, 28, 496, 8128]
No need to go all the way up to n in your inner loop. You can just use range(2, n/2 + 1), and then if sum(factors) == n - 1. Your outer loop should be through range(2, 10001) (i.e. you should test every n in this range). Note that 1 is not considered a perfect number, so we shouldn't include it in our range.
for n in range(2, 10001):
if sum(i for i in range(2, n/2 + 1) if n % i == 0) == n - 1:
print n
Well, there are quite a few simple improvements you can add.
First off, use a range(2,n). You know n%n is 0, so no need to check n at all. Just remember that the sum should be n and not 2*n (you're seeing 2*n because you've added n to the list of factors).
If you really want to speed things up, use range(2, int(math.sqrt(n))). If a is a factor of n, so is n/a. So you can append ([i, n/i]) instead of just i. Don't forget to import math'.
You want to ger all numbers from range [1 .. n] that divide n, so you should use range(2, n+1). Here is simplified version of your code:
for n in range(1, 10001):
factors = [i for i in range(1,n+1) if n % i == 0]
if sum(factors) == 2*n: print n
Not that I wanted to insult you or something, but I really don't like the style of coding, when it takes time to understand, why something works properly (I mean, why writing n+1 and then sum(factors) == 2*n; why factors = [1] if you could just written factors = [] and in range(1,n). :)
I'd write the same as (or even removed list comprehension to spare the consciousness of python newbies):
n = 1
while True:
factors = []
[factors.append(i) for i in range(1,n) if n % i == 0]
if sum(factors) == n:
print n
n += 1
The same output.

Categories

Resources