How to add number in each base case of recursion?(Python3)? - python

I want to add 1 to ans once a recursion branch reaches to where n==0 but it fails.
I tried to assign ans at first and add global in front of it but they don't work.
It's all known that we can do it in the list. That is, the base case can process ans.append(1) for ans=[]. I'm confused about what I should do here.
# Type: int n
def func(n)
def climb(n):
if n == 0:
ans += 1
elif n < 0:
ans += 0
else:
climb(n - 1)
climb(n - 2)
ans = 0
climb(n)
return ans
Edit: In case you think whether I miss the return inside. No, the mechanism I want to copy is something like this, which works:
# Type: string digits
def func(digits)
dict = {...}
def dfs(comb, i):
if i == len(digits):
ans.append(comb)
else:
for letter in dict[digits[i]]:
dfs(comb + letter, i + 1)
ans = []
if digits:
dfs("", 0)
return ans

Your code cannot parse correctly:
In your original question version, the return appeared outside of any function
ans is not defined inside climb, and you cannot modify a variable outside of climb without using a declaration with nonlocal or similar
Not a problem, but ans += 0 is a no-op.
Here is how the code can be made to parse and run:
def func(n):
def climb(n):
nonlocal ans
if n == 0:
ans += 1
elif n > 0:
climb(n - 1)
climb(n - 2)
ans = 0
climb(n)
return ans
print(func(5)) # 8
However, this way of working makes climb a function with side-effect, i.e. it is not pure. This is not best practice. You could make climb pure by returning the value that has to be added. This also makes it unnecessary to wrap climb into another function:
def climb(n):
if n == 0:
return 1
if n < 0:
return 0
return climb(n - 1) + climb(n - 2)
print(climb(5)) # 8
Note that neither represents an efficient solution. You could improve by using memoization.

Related

recursive digit sum of number , Is there a better way to write this functions?

[![enter image description here][1]][1]
First function returns the recursive digit sum of that number. The second function return dictionary where key is reg_dig_sum and value is count of that number occurring. when I tested it it failed giving me this
elf.assertEqual(sum_dict[0], 1)
AssertionError: 0 != 1
How can I solve this?
def reg_dig_sum(n):
x = sum(int(digit) for digit in str(n))
if x < 10:
return x
else:
return reg_dig_sum(x)
def distr_of_rec_digit_sums(low=0, high=1500):
distr = {}
for x in range(low, high):
if reg_dig_sum(x) not in distr:
distr[reg_dig_sum(x)] = 0
else:
distr[reg_dig_sum(x)] += 1
return distr
The problem I can think is your count for each reg_dig_sum will be one less than what it should be. That's the reason assertion condition is failing.
You can fix this logical error by initializing distr to either 1 or by removing else condition.
I would also suggest to use other alternatives like defaultdict to take care of initialization for you.
def distr_of_rec_digit_sums(low=0, high=1500):
distr = {}
for x in range(low, high):
if reg_dig_sum(x) not in distr:
distr[reg_dig_sum(x)] = 1 # this should be initialized to 1 for first occurance.
else:
distr[reg_dig_sum(x)] += 1
return distr
Using defaultdict
from collections import defaultdict
def distr_of_rec_digit_sums(low=0, high=1500):
distr = defaultdict(int)
for x in range(low, high):
distr[reg_dig_sum(x)] += 1
return distr
See previous comments and answers regarding changing 0 to 1
Also try to use much simpler code for reg_dig_sum with the same result:
def reg_dig_sum(n):
return (n - 1) % 9 + 1
I've used a simple function to do this for a long time:
def sum_digits(num):
if num <= 9:
return num
num = int(num / 10) + num - int(num / 10) * 10
''' takes the last digit of num off, and adds it to num. '''
return sum_digits(num)
There are a lot of things you can find with this function. Try this on the power series, and you'll see what I mean. Really any mathematical function you could use on a number line will return interesting patterns; this function helps you see part of that.

Why is this code not running fully? It doesn't run line 53

I made myself an exercise with python since I am new. I wanted to make a rever LMC calculator ( Least common multiple ) but for some reason, something as simple as a print in a loop doesn't seem o work for me. I would appreciate some help since I am stuck on this weird issue for 20 minutes now. Here is the code:
import random
import sys
def print_list():
count_4_print = 0
while count_4_print < len(values):
print(values[count_4_print])
count_4_print += 1
def lcm(x, y):
if x > y:
greater = x
else:
greater = y
while True:
if (greater % x == 0) and (greater % y == 0):
lcm1 = greater
break
greater += 1
return lcm1
def guess(index, first_guess, second_guess):
num = 1
while lcm(first_guess, second_guess) != values[num - 1]:
first_guess = random.randrange(1, 1000000)
second_guess = random.randrange(1, 1000000)
num += 1
num = 1
if lcm(first_guess, second_guess) == values[num - 1]:
return first_guess, second_guess
num += 1
lineN = int(input())
values = []
count_4_add = 0
count_4_guess = 0
for x in range(lineN):
values.append(int(input()))
count_4_add += 1
if count_4_add >= lineN:
break
print_list()
for x in range(lineN + 1):
first, second = guess(count_4_guess, 1, 1)
count_4_guess += 1
print(first + second)
# this ^^^ doesn't work for some reason
Line 57 is in the while loop with count_4_guess. Right above this text, it says print(first_guess + second_guess)
Edit: The code is supposed to take in an int x and then prompt for x values. The outputs are the inputs without x and LMC(output1, output2) where the "LMC" is one of the values. This is done for each of the values, x times. What it actually does is just the first part. It takes the x and prompts for x outputs and then prints them but doesn't process the data (or it just doesn't print it)
Note: From looking at your comments and edits it seems that you are lacking some basic knowledge and/or understanding of things. I strongly encourage you to study more programming, computer science and python before attempting to create entire programs like this.
It is tough to answer your question properly since many aspects are unclear, so I will update my answer to reflect any relevant changes in your post.
Now, onto my answer. First, I will go over some of your code and attempt to give feedback on what could improved. Then, I will present two ways to compute the least common multiple (LCM) in python.
Code review
Code:
def print_list():
count_4_print = 0
while count_4_print < len(values):
print(values[count_4_print])
count_4_print += 1
Notes:
Where are the parameters? It was already mentioned in a few comments, but the importance of this cannot be stressed enough! (see the note at the beginning of my comment)
It appears that you are trying to print each element of a list on a new line. You can do that with print(*my_list, sep='\n').
That while loop is not how you should iterate over the elements of a list. Instead, use a for loop: for element in (my_list):.
Code:
def lcm(x, y):
if x > y:
greater = x
else:
greater = y
while True:
if (greater % x == 0) and (greater % y == 0):
lcm1 = greater
break
greater += 1
return lcm1
Notes:
This is not a correct algorithm for the LCM, since it crashes when both numbers are 0.
The comparison of a and b can be replaced with greater = max(x, y).
See the solution I posted below for a different way of writing this same algorithm.
Code:
def guess(index, first_guess, second_guess):
num = 1
while lcm(first_guess, second_guess) != values[num - 1]:
first_guess = random.randrange(1, 1000000)
second_guess = random.randrange(1, 1000000)
num += 1
num = 1
if lcm(first_guess, second_guess) == values[num - 1]:
return first_guess, second_guess
num += 1
Notes:
The line num += 1 comes immediately after return first_guess, second_guess, which means it is never executed. Somehow the mistakes cancel each other out since, as far as I can tell, it wouldn't do anything anyway if it were executed.
if lcm(first_guess, second_guess) == values[num - 1]: is completely redundant, since the while loop above checks the exact same condition.
In fact, not only is it redundant it is also fundamentally broken, as mentioned in this comment by user b_c.
Unfortunately I cannot say much more on this function since it is too difficult for me to understand its purpose.
Code:
lineN = int(input())
values = []
count_4_add = 0
count_4_guess = 0
for x in range(lineN):
values.append(int(input()))
count_4_add += 1
if count_4_add >= lineN:
break
print_list()
Notes:
As explained previously, print_list() should not be a thing.
lineN should be changed to line_n, or even better, something like num_in_vals.
count_4_add will always be equal to lineN at the end of your for loop.
Building on the previous point, the check if count_4_add >= lineN is useless.
In conclusion, count_4_add and count_4_guess are completely unnecessary and detrimental to the program.
The for loop produces values in the variable x which is never used. You can replace an unused variable with _: for _ in range(10):.
Since your input code is simple you could probably get away with something like in_vals = [int(input(f'Enter value number {i}: ')) for i in range(1, num_in_vals+1)]. Again, this depends on what it is you're actually trying to do.
LCM Implementations
According to the Wikipedia article referenced earlier, the best way to calculate the LCM is using the greatest common denominator.
import math
def lcm(a: int, b: int) -> int:
if a == b:
res = a
else:
res = abs(a * b) // math.gcd(a, b)
return res
This second method is one possible brute force solution, which is similar to how the one you are currently using should be written.
def lcm(a, b):
if a == b:
res = a
else:
max_mult = a * b
res = max_mult
great = max(a, b)
small = min(a, b)
for i in range(great, max_mult, great):
if i % small == 0:
res = i
break
return res
This final method works for any number of inputs.
import math
import functools
def lcm_simp(a: int, b: int) -> int:
if a == b:
res = a
else:
res = abs(a * b) // math.gcd(a, b)
return res
def lcm(*args: int) -> int:
return functools.reduce(lcm_simp, args)
Oof, that ended up being way longer than I expected. Anyway, let me know if anything is unclear, if I've made a mistake, or if you have any further questions! :)

Looking to understand the logical breakdown of this code block

Just playing with some basic code (factorials) but cannot quite get my head around how this is achieving the correct result. The result on each loop does not seem to be stored anywhere - so how does the code remember the iterated value? (I know there are modules - this is just a logic exercise)
def factoral2(num):
if num == 0:
return 1
return num * factoral2(num - 1)
Above is the method that I'm not quite sure how works
def factoral(num):
number = []
for i in range(0, num):
number.append(num)
num -= 1
print(number)
product = 1
for x in number:
product *= x
return product
This was my interpretation of its logic, which is obviously a bit more verbose than what's ideal
Both work - just trying to understand the logic of the optimised version
ok, let's run through an example lets say the user inputs 2 -> num=2.
First, we have to build our way down (essentially we need num to equal 0)
first, we call factorial(2), and check the if statement which turns out to be false.
therefor factorial(2) = return num * factorial(num-1) = return 2 * factorial(1)
the above statement needs to compute the value for factorial(1) before it can return a value, so let's go ahead and do that
first, we call factorial(1), and check the if statement which == false
therefor factorial(1) = return num * factorial(num-1) = return 1* factorial(0)
the above statement needs to compute the value for factorial(0) before it can return a value, so let's go ahead and do that also
first, we call factorial(0), and check the if statement which == true
therefor factorial(0) = 1
Now we can start building up
factorial(0) = 1
now just start plugging in values
we said factorial(1) = return 1* factorial(0) = return 1* 1 = return 1
factorial(1) = 1
now we can plug in some more values
we said factorial(2) = return 2* factorial(1) = return 2 * 1 = return 2
factorial(2) = 2
Thanks to Andreas and below_avg_st for your help.
Makes alot more sense now.
As I see it:
Recursive functions generate an infinite loop if a condition to break is not allocated.
(I've re-written the below to state that logic abit more). If X does not equal 0, keep looping through the function while decrementing X.
When the loop does break - (because X = 0) assign a value of 1 - to exit the loop.
def test(x):
if x != 0:
return x * test(x-1)
else:
return 1
test(4)
Thanks to all for your help
It's a recursive function that calls itself, giving num - 1 as argument.
The function supplied:
def factoral2(num):
if num == 0:
return 1
return num * factoral2(num-1)
"gets expanded" into this:
def factoral2(num):
result = 1
while (num != 0):
result *= num
num -= 1
return result
value = factoral2(4) can be illustrated as such:
num = 4
num = 3
num = 2
num = 1
num = 0; return 1
result = 1
result = 2 * 1
result = 3 * 2
result = 4 * 6
value = 24
I'd also like to note out a better non-recursive version of the factorial function, compared to the one you crafted, that unnecessarily creates and fills a list.
def factorial(n):
if n < 0:
raise ValueError("The factorial value may only be calculated on positive integers")
product = 1
for i in range(2, n + 1):
product *= i
return product
– or just a simplified recursive one, using the "ternary operator":
def factorial(n):
if n < 0:
raise ValueError("The factorial value may only be calculated on positive integers")
return 1 if n == 0 else n * factorial(n - 1)

Python Pure recursion - Divisor - One input

What is the recursive call (or inductive steps) for a function that returns the number of integers from 1 to N, which evenly divide N. The idea is to concieve a pure recursive code in python for this function. No 'for' or 'while' loops, neither modules can be used. The function num_of_divisors(42) returns 8, representing 1, 2, 3, 6, 7, 14, 21, and 42 as divisors of 42.
def num_of_divisors(n):
return sum(1 if n % i==0 else 0 for i in range(((n+1)**0.5)//1)
Good luck explaining it to your teacher!
If you really can't use for loops (?????????) then this is impossible without simulating one.
def stupid_num_of_divisors_assigned_by_shortsighted_teacher(n, loop_num=1):
"""I had to copy this from Stack Overflow because it's such an
inane restriction it's actually harmful to learning the language
"""
if loop_num <= (n+1) ** 0.5:
if n % loop_num == 0:
return 2 + \
stupid_num_of_divisors_assigned_by_shortsighted_teacher(n, loop_num+1)
else:
return stupid_num_of_divisors_assigned_by_shortsighted_teacher(n, loop_num+1)
else:
if n % loop_num == 0:
return 1
Bonus points: explain why you're adding 2 in the first conditional, but only 1 in the second conditional!
Here you go buddy your teacher'll be happy.
def _num_of_divisors(n, k):
if (k == 0):
return 0
return _num_of_divisors(n, k-1) + (n % k == 0)
def num_of_divisors(n):
return _num_of_divisors(n, n)
It's easier than you think to convert such a simple problem from a loop to a recursive function.
Start with a loop implementation:
n = 42
result = []
for i in range(n+1):
if n % i == 0:
result.append(i)
then write a function
def num_of_divisors_helper(i, n, result):
if <condition when a number should be added to result>:
result.append(n)
# Termination condition
if <when should it stop>:
return
# Recursion
num_of_divisors_helper(i+1, n, result)
Then you define a wrapper function num_of_divisors that calls num_of_divisors_helper. You should be able to fill the gaps in the recursive function and write the wrapper function yourself.
It's a simple, inefficient solution, but it matches your terms.
Without using %
def is_divisible(n, i, k):
if k > n:
return False
if n - i*k == 0:
return True
else:
return is_divisible(n, i, k+1)
def num_of_divisors(n, i=1):
if i > n/2:
return 1
if is_divisible(n, i, 1):
return 1 + num_of_divisors(n, i+1)
else:
return num_of_divisors(n, i+1)
num_of_divisors(42) -> 8
def n_divisors(n,t=1):
return (not n%t)+(n_divisors(n,t+1) if t < n else 0)
good luck on the test later ... better hit those books for real, go to class and take notes...
with just one input i guess
t=0
def n_divisors(n):
global t
t += 1
return (not n%t)+(n_divisors(n) if t < n else 0)

Python List Indexing Error

def getPrimeList(check):
storedprimes = []
i = 2
while i <= check:
if isPrime(check):
storedprimes = storedprimes + [i]
i = i + 1
return storedprimes
def getPrimeFact(check):
primelist = getPrimeList(check)
prime_fact = []
i = 0
while check !=1:
if check%primelist[i]==0:
prime_fact=prime_fact+[primelist[i]]
check = check/primelist[i]
i = i + 1
if i == len(primelist):
i = 0
return prime_fact
def getGCF(checks):
a=0
listofprimefacts=[]
while a<len(checks):
listofprimefacts=listofprimefacts+[getPrimeFact(checks[a])]
a=a+1
b=0
storedprimes=[]
while b<len(primefactlist):
c=0
while c<len(listofprimefacts[b]):
if listofprimefacts[b][c] not in storedprimes:
storedprimes=storedprimes+[listofprimefacts[b][c]]
c=c+1
b=b+1
prime_exp=[]
d=0
while d<len(storedprimes):
prime_exp=prime_exp+[0]
d=d+1
e=0
while e<len(storedprimes):
f=0
while f<len(listofprimefacts):
if f==0:
prime_exp[e]=listofprimefacts[f].count(storedprimes[e])
elif prime_exp[e]-(listofprimefacts[f].count(storedprimes[e]))>0:
prime_exp[e]=listofprimefacts[f].count(storedprimes[e])
f=f+1
e=e+1
g=0
GCF=1
while g<len(primelist):
GCF=GCF*(storedprime[g]**prime_exp[g])
g=g+1
return GCF
I am creating a program that will use these functions for the purpose of calculating fractions; however, after testing my GCF function in the shell I keep getting a list indexing error. I have no idea, where the error is coming from considering im 99% sure there is no problems with my indexes, usually i would not post such a "fixable" problem in SO but this time i just have no idea what the problem is, thanks again.
Oh and heres the exact error
File "<pyshell#1>", line 1, in <module>
getGCF(checks)
File "E:\CompProgramming\MidtermFuncts.py", line 31, in getGCF
listofprimefacts=listofprimefacts+[getPrimeFact(checks[a])]
File "E:\CompProgramming\MidtermFuncts.py", line 20, in getPrimeFact
if check%primelist[i]==0:
IndexError: list index out of range
You might want to re-think how you attack this problem. In its current form, your code is really hard to work with.
Here's how I'd do it:
def is_prime(n):
for i in range(2, int(n ** 0.5) + 1):
if n % i == 0:
return False
return True
def prime_factors(number):
factors = []
for i in range(2, number / 2):
if number % i == 0 and is_prime(i):
factors.append(i)
return factors
def gcf(numbers):
common_factors = prime_factors(numbers[0])
for number in numbers[1:]:
new_factors = prime_factors(number)
common_factors = [factor for factor in common_factors if factor in new_factors]
return max(common_factors)
This line right here:
common_factors = [factor for factor in common_factors if factor in new_factors]
Is a list comprehension. You can unroll it into another for loop:
temp = []
for factor in common_factors:
if factor in new_factors:
temp.append(factor)
common_factors = list(temp) # Pass by value, not by reference
You mixed up i and check in your getPrimeList() function; you test if check is a prime, not i; here is the correct function:
def getPrimeList(check):
storedprimes = []
i = 2
while i <= check:
if isPrime(i): # *not* `check`!
storedprimes = storedprimes + [i]
i = i + 1
return storedprimes
This, primelist will be set to an empty list (as getPrimeList(check) returns an empty list) and your primelist[i] (for any i) will fail with an index error.
Another way for primelist to be empty is when isPrime() never returns True; you don't show us that function to verify it.
Your next error is in getGCF(); you define a listofprimefacts variable (a list) first, but later refer to a non-existing primefactlist variable, leading to a NameError. The next name error is going to be primelist further in that function.
You really want to re-read the Python tutorial; you are missing out on many python idioms in your code; specifically on how to create loops over sequences (hint: for check in checks: is easier to use than a while loop with an index variable) and how to append items to a list.
My personal toolkit defines this:
from math import sqrt
def prime_factors(num, start=2):
"""Return all prime factors (ordered) of num in a list"""
candidates = xrange(start, int(sqrt(num)) + 1)
factor = next((x for x in candidates if (num % x == 0)), None)
return ([factor] + prime_factors(num / factor, factor) if factor else [num])
which doesn't need a isPrime() test.

Categories