Different results from for-loop and while-loop for prime factorization in Python 3 - python-3.x

I have written a function that returns the prime factors of a given integer. For the cases I tested, it seems to work alright. Here is the original function.
def prime_factors_2(num: int) -> set:
factors = []
while num % 2 == 0:
factors.append(2)
num //= 2
i = 3
while i <= int(sqrt(num)) + 1:
if num % i == 0:
factors.append(i)
num //= i
else:
i += 2
if num != 1:
factors.append(num)
return set(factors)
# num = 867844
# Output = {601, 2, 19}
While messing around with the code, I tried to implement the same but with a for loop instead of a while loop (as I prefer to use a for loop when counting is involved). This is the code for the second function.
def prime_factors_1(num: int) -> set:
factors = []
while num % 2 == 0:
factors.append(2)
num //= 2
for i in range(3, int(sqrt(num)) + 1, 2):
if num % i == 0:
factors.append(i)
num //= i
print(num)
if num != 1:
factors.append(num)
return set(factors)
# num = 867844
# Output = {2, 19, 11419}
For some reason, it no longer factors the 11419 into 601 and 19. Are both the loops not equivalent? Or am I making some mistake while translating the while loop to a for loop? I know that there is no practical difference between the two loops in this case, but I want to know this out of pure curiosity.

Problem is that in your "while loop", you are incrementing the value of "i" by 2 only when the "if" condition is not satisfied, but in the case of "for loop", i is getting incremented by 2 in each iteration.
So if you'll do something like:
while i <= int(sqrt(num)) + 1:
if num % i == 0:
factors.append(i)
num //= i
i += 2
Then the prime_factors_2 function would also result in the same answer as the prime_factors_1 function

There is a slight difference between the two functions.
If you look closely at prime_factors_2, in the while loop, the counter doesn't get incremented when the if condition is satisfied.
On the other hand, in prime_factors_1, in the for loop, the counter gets incremented in every iteration regardless of the if condition.
There is no way to control the counter from within a for loop, so the while loop implementation is the only correct approach.

Related

What is the problem with this for loop in python?

I want to create a function to calculate the sum of number which are multiples of 3.
What is the problem here, because I get numbers repeated 3 times until I get to 18, which is out of range. I don't understand.
summ = 0
for n in range(10):
if n % 3 == 0:
summ = summ+n
print(summ)
Try:
summ = 0
for n in range(10):
if n % 3 == 0:
summ = summ+n
print(summ)
Your code print(summ) is inside the loop, meaning it will print multiple times (as many times as the loop runs). Moving it outside of the loop will only make it print once after the loop is done running.

recursive solution for coin change problem

i need to write an algorithm that receives a number and a list of numbers and returns the number of possible combinations of numbers from the list that can create the sum number. for example: def coin(5,[1,2,5,6] should return the number 4 because there are 4 possible combinations from the list that can create together the number 5. below there is the code that i tried but it does not work. the output is 6 instead of 4 and i would love some help in understanding why.
def coin(n,lst):
if n<=1:
return 1
else:
total=0
for i in range(len(lst)):
change=lst[i]
if change>n:
continue
else:
result=coin(n-change,lst[i:])
if result>0:
total+=result
return total
print(coin(5,[1,2,5,6]))
The mistake is in the base case:
if n<=1:
return 1
This is only valid if 1 is one of the allowed coins. But in your recursive case, you slice the list at lst[i:], so not all coins will be allowed every time. Sometimes, 1 isn't one of the allowed coins, in which case there are zero ways to make a total of 1, not one way. To fix it, write something like:
if n <= 1:
if n == 0 or n in lst:
return 1
else:
return 0
This is correct because you can make change for n in the base case either if n is 0 (we can always make 0), or if n is 1 and 1 is one of the allowed coins.
That said, it would be simpler to let the recursive case handle 1, so the base case only needs to handle 0; this is also correct:
if n == 0:
return 1
int coinCount( int C[], int m, int n )
{
// if n is 0 return 1
if (n == 0)
return 1;
// If n is less than 0 then no solution exists
if (n < 0)
return 0;
// If there are no coins and n is greater than 0, then no solution exists
if (m <=0 && n > 0)
return 0;
return coinCount( C, m - 1, n ) + coinCount( C, m, n-C[m-1] );
}

Python 3, any better/cleaner way to write these functions that use for loops?

I'm trying to write code in the most simplest and cleanest way possible. I've found a few ways to shorten and simplify my code through functions that I've never seen before or through using other methods. I'd like to expand my knowledge on writing code using various (but simple) methods, and also expand my function 'vocabulary'.
Here are the functions:
1. Perfect number:
If a number's divisors' sum is equal to the number itself, it is a perfect number. We dont count the number itself as a divisor. E.g. 6's divisors are 1, 2, 3. The sum of the divisors is 6. Therefore 6 is a perfect number.
def perfect_number(num):
if type(num) != int or num < 0:
return None
divisors = []
total = 0
for x in range(num):
if num % (x+1) == 0:
if num != x+1:
divisors += [x+1]
for x in divisors:
total += x
if total == num:
return True
return False
2. Pattern:
A function that takes a positive integer and prints a pattern as follows:
pattern(1): '#-'
pattern(2): '#-#--'
pattern(5): '#-#--#---#----#-----'
def pattern(num):
if type(num) != int or num < 0:
return None
output = ''
for x in range(num):
output += '#'+('-'*(x+1))
return output
3. Reversed Numbers:
A function that takes 2 integers. It goes through every number in the range between those 2 numbers, if one of those numbers is a palindrome (the same thing backwards e.g. 151 is a 'palindrome'), it will increase a variable by 1. That variable is then returned.
invert_number(num) returns the opposite of num as an integer.
def reversed_numbers(low, high):
output = 0
for x in range(low,high+1):
if invert_number(x) == x:
output += 1
return output
It is assumed that low is lower than high.
If I broke a rule or if this doesnt fit here, please tell me where I can post it/how I can improve. Thanks :)

power (a, n) in PYTHON

POwer in Python. How to write code to display a ^ n using funсtion?
why doesn't this code working?
a = int(input())
n = int(input())
def power(a, n):
for i in range (n):
a=1
a *= n
print(power (a, n))
Few errors:
Changing a will lose your power parameter, use result (or something else).
Move setting result = 1 outside your loop to do so once.
Multiply by a not by n.
Use return to return a value from the function
def power(a, n):
result = 1 # 1 + 2
for _ in range (n):
result *= a # 3
return result # 4
Style notes:
Setting/mutating a parameter is considered bad practice (unless explicitly needed), even if it is immutable as is here.
If you're not going to use the loop variable, you can let the reader know by using the conventional _ to indicate it (_ is a legal variable name, but it is conventional to use it when not needing the variable).
Tip: you can simple use a**n
It doesn't work because your function doesn't return the end value. Add return a to the end of the function.
ALSO:
That is not how a to the power of n is is calculated.
A proper solution:
def power(a,n):
pow_a = a
if n is 0:
return 1
for _ in range(n-1): # Substracting 1 from the input variable n
pow_a *= a # because n==2 means a*a already.
return pow_a
and if you want to be really cool, recursion is the way:
def power_recursive(a,n):
if n is 0:
return 1
elif n is 1:
return a
else:
a *= power_recursive(a,n-1)
return a

Trying to understand this simple python code

I was reading Jeff Knupp's blog and I came across this easy little script:
import math
def is_prime(n):
if n > 1:
if n == 2:
return True
if n % 2 == 0:
return False
for current in range(3, int(math.sqrt(n) + 1), 2):
if n % current == 0:
return False
return True
return False
print(is_prime(17))
(note: I added the import math at the beginning. You can see the original here:
http://www.jeffknupp.com/blog/2013/04/07/improve-your-python-yield-and-generators-explained/)
This is all pretty straightforward and I get the majority of it, but I'm not sure what's going on with his use of the range function. I haven't ever used it this way or seen anyone else use it this way, but then I'm a beginner. What does it mean for the range function to have three parameters, and how does this accomplish testing for primeness?
Also (and apologies if this is a stupid question), but the very last 'return False' statement. That is there so that if a number is passed to the function that is less than one (and thus not able to be prime), the function won't even waste its time evaluating that number, right?
The third is the step. It iterates through every odd number less than or equal to the square root of the input (3, 5, 7, etc.).
import math #import math module
def is_prime(n): #define is_prime function and assign variable n to its argument (n = 17 in this example).
if n > 1: #check if n (its argument) is greater than one, if so, continue; else return False (this is the last return in the function).
if n == 2: #check if n equals 2, it so return True and exit.
return True
if n % 2 == 0: #check if the remainder of n divided by two equas 0, if so, return False (is not prime) and exit.
return False
for current in range(3, int(math.sqrt(n) + 1), 2): #use range function to generate a sequence starting with value 3 up to, but not including, the truncated value of the square root of n, plus 1. Once you have this secuence give me every other number ( 3, 5, 7, etc)
if n % current == 0: #Check every value from the above secuence and if the remainder of n divided by that value is 0, return False (it's not prime)
return False
return True #if not number in the secuence divided n with a zero remainder then n is prime, return True and exit.
return False
print(is_prime(17))

Resources