Why is my list comprehension only grabbing 0s? - python

LINE 11: List comprehension is only getting 0s?
please answer with the solution and nothing unrelated.
SUM_OF_DIVISORS = 0 # SUM OF THE DIVISORS OF (N)
def DIVISORS_SUM(N = 0):
global SUM_OF_DIVISORS
SUM_OF_DIVISORS -= N # MAKING SURE THAT N ITSELF IS EXCLUDED
if N != 0:
NUMBER = N
try:
DIVISORS = [X for X in range(0, N) if X%NUMBER == 0] # LIST COMPREHENSION (QUICK WAY OF FINDING DIVISORS)
X: int
for X in DIVISORS: # CREATING A FOR LOOP TO ADD TO SUM.
SUM_OF_DIVISORS += X
print(SUM_OF_DIVISORS)
except:
print("CAN'T CREATE SUM OF DIVISORS WITH 0.")
DIVISORS_SUM(0) # RETURNS ERROR BECAUSE N ITSELF MUST BE EXCLUDED
DIVISORS_SUM(3) # RETURNS 1 BECAUSE SUM OF DIVISORS WITH N EXCLUDED ADDS UP TO 1
DIVISORS_SUM(36) # RETURNS 36 BECAUSE SUM OF DIVISORS WITH N EXCLUDED ADDS UP TO 1
DIVISORS_SUM(102) # RETURNS 102 BECAUSE SUM OF DIVISORS WITH N EXCLUDED ADDS UP TO 1

Change:
DIVISORS = [X for X in range(0, N) if X%NUMBER == 0]
to:
DIVISORS = [X for X in range(1, N) if (NUMBER % X) == 0]
Note the 1 not zero to avoid ZeroDivisionError: integer division or modulo by zero

Related

Adding the highest odd and even in a list

I have a list and I'm trying to write a program that finds the highest odd and even number and add them together then print the number.
numbers = [2,3,4,5,6,1,0,7]
def solution(numbers):
lodd = -1
leven = -1
for n in numbers:
n = int(n)
if n % 2 == 0 and n > leven:
leven = n
print(n)
for n in numbers:
n = int(n)
if n % 2 != 0 and n > lodd:
lodd = n
print(n)
solution(numbers)
You could do something like :
odds = [element for element in numbers if element % 2 != 0]
evens = [element for element in numbers if element % 2 == 0]
print(max(odds) + max(evens))
Why use two loops where you could just iterate once?
Iterate and save the max per condition (odd or even), then sum the result.
positive numbers only
numbers = [2,3,4,5,6,1,0,7]
out = {0: 0, 1: 0}
for n in numbers:
if n>out[n%2]:
out[n%2] = n
sum(out.values())
# 13
more generic code to handle negative numbers as well and missing odd/even values
This handles possible missing evens or odds:
numbers = [1,3,1,5,1,-7]
out = {0: None, 1: None}
for n in numbers:
k = n%2
if out[k] is None or n>out[k]:
out[k] = n
sum(v for v in out.values() if v)
# 5

Trying to find if a number exists with total of X positive factors out of which there are K distinct prime factors

If the number is of the form of a^bc^de^f where a,c and e are prime numbers then total number of factors are (b+1)(d+1)(f+1).
I approached the problem in the following way-
If there are more than or equal to K prime factors of X then it is possible otherwise it is not.
I am getting a TLE error.
We have to print 1 if such a number exists and 0 if not.
import math
T = int(input())
for _ in range(0,T):
flag = 0
X,K = map(int,input().split())
if K == 0:
if X == 1:
print(1)
else:
print(0)
elif K == 1:
if X >= 2:
print(1)
else:
print(0)
elif K>=2:
if X >= 2**K:
count = 0
while ((X % 2 > 0) == False):
X >>= 1
count += 1
K = K-1
#if (count > 0):
# count1 = count
for i in range(3, int(math.sqrt(X)) + 1):
while (X % i == 0):
X = int(X / i)
K = K-1
#if (count > count1):
# n.append(count)
i += 2
if (X > 2):
K = K-1
if K <= 0:
print(1)
else:
print(0)
else:
print(0) ***
The constraints are-
T<= 10^3
X,K <= 10^9
Any way to reduce the runtime?
You can use a simpler recursive function with a Counter object to determine if there are at least K prime factors forming X.
This function will not only give you the list of prime factors but will also provide a count (power) of each prime. The sum of these counts is the maximum number of factors of X.
from collections import Counter
def primeFactors(N):
for f in range(1,int(N**0.5)+1,2): # stepping by 2 gives a 30% speed-up
if f==1: f=2
if N%f==0:
return Counter([f]) + primeFactors(N//f)
return Counter([N])
X = 368640000
K = 21
result = 1 if sum(primeFactors(X).values())>=K else 0
print(result) # 1
This runs in 0.16 seconds for 1000 random test cases on my laptop. The worst case scenario takes 1.06 seconds if all 1000 test cases have X=999999937 (largest prime below 10^9)
[EDIT] here is a variant of the solution using a simple dictionary. It is a bit more code but has the same performance as with the counter object
def primeFactors(N):
for f in range(1,int(N**0.5)+1,2):
if f==1: f = 2
if N%f==0:
result = primeFactors(N//f)
result[f] = result.get(f,0)+1
return result
return {N:1}
[EDIT2] Here is an optimized version of your original code.
These are the optimizations I did:
Removed unnecessary logic and conditions (e.g. X>=2**K)
Fixed the 2 by 2 stepping range that didn't work (having i+=2 inside the loop does not make it step by 2).
Made the factor loop break when the squared factor (i) went beyond the remaining X (instead of always looping all the way to the square root of the original X).
Also broke the loop when the K target is reached.
Removed the special code to process prime=2.
Made sure to use only integer arithmetic (// instead of /)
Eliminated the square root calculation (using i x i < X to break the loop).
...
def OP(X,K):
if K == 0: return int(X==1)
if K == 1: return int(X>=2)
for i in range(1,X,2): # stride by two until break
if i==1: i=2 # handle first prime (2)
while not X % i: # reduce X and K for prime factors
X //= i # X becomes other factor in X = i * X'
K -= 1 # one less prime factor to find
if K<1 or i*i>X:
break # break when max prime reached (or K primes)
return int(K<=0)
With these changes, the calculation perform almost as fast as the primeFactors() function (roughly 50% slower).

Am trying to write a code that will print the numbers within the range of 'a' that are not divisible by y

sample.py
y = [2,3,4,5,6,7,8,9] # array
Function is created below
def _div(a): # Needed to create a function
z = 0 # constant
for x in range(1 , a +1): # To check for all the numbers within the range of a
while z < 8:
if x % y[z] != 0 : # To check if the value of x is divisible by any of the value in the array
j = [x]
Print (j[0])
z += 1
Calling function
div(15) # not showing any result on Python
end Python
Loop over all values in the range from 1 to the given number. For each value check if the modulo operation gives a value other than 0 for all divisors. If yes, add the value to the list.
Now we can write that down in Python code.
def _div(number, divisors):
result = []
for value in range(1, number + 1):
if all(value % divisor != 0 for divisor in divisors):
result.append(value)
return result
y = [2, 3, 4, 5, 6, 7, 8, 9]
print(_div(15, y))
This will give you [1, 11, 13].
There is a possible optimization. Instead of checking if the current value is not divisible by all divisors we can check if the value is divisible by any divisor. This will end the check (shortcut) when a matching divisor is found.
So replace
if all(value % divisor != 0 for divisor in divisors):
result.append(value)
with
if not any(value % divisor == 0 for divisor in divisors):
result.append(value)
I replaced the variable names in the function by more meaningful ones. The function itself would deserve a better name too. At least I added the list of divisors as a parameter because it's a bad idea to work with global states in a function.
With a list comprehension you could even make a one-liner out of this but I prefer the more readable multiline version.
def _div(number, divisors):
return [value for value in range(1, number + 1) if not any(value % divisor == 0 for divisor in divisors)]
def not_dividable_by(factor, quotient_list, unique_output=True):
"""
Args:
factor(int): All numbers from 0-factor are calculated
quotient_list(list): List of to test if factor is divisable with
unique_output(bool): Numbers may occur multiple times if False
Returns:
list: with integers of numbers not divisable by any of 0-factor
"""
result = []
for i in range(0, factor + 1):
for x in quotient_list:
if i % x:
if x not in result or not unique_output:
result.append(x)
return sorted(result) if unique_output else result
print(not_dividable_by(15, [2,3,4,5,6,7,8,9]))
But most of the times the output will be all numbers in the list.

Python algorithm for finding perfect numbers

Please could you help correct this code! It's for finding all perfect numbers below the set limit of 10,000, I've used comments to explain what I'm doing. Thanks!
#Stores list of factors and first perfect number
facs = []
x = 1
#Defines function for finding factors
def findfactors(num):
#Creates for loop to find all factors of num
for i in range(1, num + 1):
if num % i == 0:
#Stores factor in facs
facs.append(i)
#Activates loop
while x < 10000:
#Finds factors of x and appends them to list
findfactors(x)
#Finds sum of list
facsum = sum(facs)
#Makes decision based on sum of factors and original number
if facsum == x:
#Ouputs and increases x
print(x)
x += 1
else:
#Increases x
x += 1
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). The first perfect number is 6. The next perfect number
is 28. This is followed by the perfect numbers 496 and 8128.
(Wikipedia)
You have to exclude the number itself from the factors list.
Also, for each x you have to start with the empty facs and then append to it. You don't want previous numbers factors in that list. The following code works.
x = 1
def findfactors(num):
facs = []
for i in range(1, num):
if num % i == 0:
facs.append(i)
return facs
while x < 10000:
facs = findfactors(x)
facsum = sum(facs)
if facsum == x:
print(x)
x += 1
else:
x += 1
This is a simpler implementation of your logic.
x = 1
#Defines function for finding factors
def isperfectnum(num):
sum=0
#Creates for loop to find all factors of num
for i in range(1, num ):
if num % i == 0:
sum=sum+i
if sum==num:
return TRUE
else
return FALSE
#Activates loop
while x < 10000:
#Finds perfect numbers
if isperfectnum(x):
print(x)
x=x+1
Found the problem!
Should have been:
for i in range(1, num - 1)
Rather than:
for i in range(1, num + 1)
Thanks to all contributors!
intialize list inside the def and return and the range should not include the original num so range would be from 1 to num which includes 1 but excludes orginal num so it will generate range from 1 to num-1
#Stores list of factors and first perfect number
x = 1
#Defines function for finding factors
def findfactors(num):
facs = []
for i in range(1, num):
if num % i == 0:
#Stores factor in facs
facs.append(i)
return facs
#Activates loop
while x < 1000:
#Finds factors of x and appends them to list
facs=findfactors(x)
#Finds sum of list
facsum = sum(facs)
#Makes decision based on sum of factors and original number
if facsum == x:
#Ouputs and increases x
print(x)
x+= 1
Much faster than generating list
Approach from What is the most efficient way of finding all the factors of a number in Python?
#Stores list of factors and first perfect number
x = 1
#Defines function for finding factors
from functools import reduce
def factors(n):
return set(reduce(list.__add__,
([i, n//i] for i in range(1, int(n**0.5) + 1) if n % i == 0)))
#Activates loop
while x < 10000:
#Finds factors of x and appends them to list
facs=factors(x)
facs.remove(x) # remove original number as it is not required further
#Finds sum of list
facsum = sum(facs)
#Makes decision based on sum of factors and original number
if facsum == x:
#Ouputs and increases x
print(x)
x+= 1

How would you implement a divisor function?

The divisor function is the sum of divisors of a natural number.
Making a little research I found this to be a very good method if you want to find the divisor function of a given natural number N, so I tried to code it in Python:
def divisor_function(n):
"Returns the sum of divisors of n"
checked = [False]*100000
factors = prime_factors(n)
sum_of_divisors = 1 # It's = 1 because it will be the result of a product
for x in factors:
if checked[x]:
continue
else:
count = factors.count(x)
tmp = (x**(count+1)-1)//(x-1)
sum_of_divisors*=tmp
checked[x]=True
return sum_of_divisors
It works pretty well,but I am sure that it can be improved(e.g. : I create a list with 100000 elements,but I am not using most of them).
How would you improve/implement it?
P.S. This is prime_factors:
def prime_factors(n):
"Returns all the prime factors of a positive integer"
factors = []
d = 2
while (n > 1):
while (n%d==0):
factors.append(d)
n /= d
d = d + 1
if (d*d>n):
if (n>1): factors.append(int(n));
break;
return factors
When computing the sum of divisors, you need the factorization of n in the form p1k1 p2k2 ... — that is, you need the exponent of each prime in the factorization. At the moment you are doing this by computing a flat list of prime factors, and then calling count to work out the exponent. This is a waste of time because you can easily generate the prime factorization in the format you need in the first place, like this:
def factorization(n):
"""
Generate the prime factorization of n in the form of pairs (p, k)
where the prime p appears k times in the factorization.
>>> list(factorization(1))
[]
>>> list(factorization(24))
[(2, 3), (3, 1)]
>>> list(factorization(1001))
[(7, 1), (11, 1), (13, 1)]
"""
p = 1
while p * p < n:
p += 1
k = 0
while n % p == 0:
k += 1
n //= p
if k:
yield p, k
if n != 1:
yield n, 1
Notes on the code above:
I've transformed this code so that it generates the factorization, instead of constructing a list (by repeated calls to append) and returning it. In Python, this transformation is nearly always an improvement, because it allows you to consume elements one by one as they are generated, without having to store the whole sequence in memory.
This is the kind of function for which doctests work well.
Now computing the sum of divisors is really simple: there's no need to store the set of checked factors or to count the number of times each factor occurs. In fact you can do it in just one line:
from operator import mul
def sum_of_divisors(n):
"""
Return the sum of divisors of n.
>>> sum_of_divisors(1)
1
>>> sum_of_divisors(33550336) // 2
33550336
"""
return reduce(mul, ((p**(k+1)-1) // (p-1) for p, k in factorization(n)), 1)
You need to change two lines only:
def divisor_function(n):
"Returns the sum of divisors of n"
checked = {}
factors = prime_factors(n)
sum_of_divisors = 1 # It's = 1 because it will be the result of a product
for x in factors:
if checked.get(x,False):
continue
else:
count = factors.count(x)
tmp = (x**(count+1)-1)//(x-1)
sum_of_divisors*=tmp
checked[x]=True
return sum_of_divisors
why use dict or set - or count() - at all, when prime_factors() is guaranteed to return the factors in ascending order? You only ever deal with a previous factor. Counting can just be a part of iteration:
def divisor_function(n):
"Returns the sum of divisors of n"
factors = prime_factors(n)
sum_of_divisors = 1
count = 0; prev = 0;
for x in factors:
if x==prev:
count += 1
else:
if prev: sum_of_divisors *= (prev**(count+1)-1)//(prev-1)
count = 1; prev = x;
if prev: sum_of_divisors *= (prev**(count+1)-1)//(prev-1)
return sum_of_divisors
def sum_divisors(n):
assert n > 0
if n == 1:
return 0
sum = 1
if n % 2 == 0: # if n is even there is a need to go over even numbers
i = 2
while i < sqrt (n):
if n % i == 0:
sum = sum + i + (n//i) # if i|n then n/i is an integer so we want to add it as well
i = i + 1
if type (sqrt (n)) == int: # if sqrt(n)|n we would like to avoid adding it twice
sum = sum + sqrt (n)
else:
i = 3
while i < sqrt (n): # this loop will only go over odd numbers since 2 is not a factor
if n % i == 0:
sum = sum + i + (n//i) # if i|n then n/i is an integer so we want to add it as well
i = i + 2
if type (sqrt (n)) == int: # if sqrt(n)|n we would like to avoid adding it twice
sum = sum + sqrt (n)
return sum
Here is what I do in my Java number utilities (extensively used for Project Euler):
Generate the prime factorization with explicit exponents (see the answer by Gareth Rees).
Unfold the prime factorization in the various functions based on it. I.e., use the same algorithm as for prime factorization but directly compute the desire value instead of storing the factors and exponents.
By default test only divisors two and odd numbers. I have methods firstDivisor(n) and nextDivisor(n,d) for that.
Optionally precompute a table of least divisors for all numbers below a bound. This is very useful if you need to factorize all or most numbers below the bound (improves speed by about sqrt(limit)). I hook the table into the firstDivisor(n) and nextDivisor(n,d) methods, so this doesn't change the factorization algorithms.

Categories

Resources