Python Recursion Behavior - python

I have studied recursion, especially in Python, and think I get it.
I have learned this form:
def f_Listsum(numList):
if len(numList) == 1:
return numList[0] ## Triggers the unwinding of the recursion stack
else:
return numList[0] + f_Listsum(numList[1:]) ## Winds up the recursion stack with a shorter and shorter slice of org. list.
I get it. The recursive calls sort of "wind" things up, and then a stop or "trigger" causes the recursion to collapse into itself and consume the resulting values.
However I ran into this today:
def f_DecToBinary(v_Num):
if v_Num > 1:
f_DecToBinary(v_Num // 2)
print(v_Num % 2,end = '')
I wanted to substitute the function's "print" with a return of a string, or even a list of INTs, but I can't get it to work, as I don't understand how this recursion is operating. I see that it calls itself each time, and then initiates a collapse when v_Num == 1 or less, but it collapses to outside the "if" statement and then I get lost. When I try to assemble a STR or LIST from the collapse instead of just printing it, I errors or just the last digit returned.
My questions are: How does f_DecToBinary work/function, and how can I capture the output into a string?
Some examples:
print(f_Listsum([1,3,5,7,9])) ## 25
print()
f_DecToBinary(15) ## 1111
Thanks

Follow the typical flow through the function. It will call itself, which causes some output, then it prints a single digit. So the single digit comes at the end of the previous ones. To return the result instead of printing it, you need to take the result of the recursive call and add the current result to the end of it.

def DecToBinary(n):
if n >= 2:
return DecToBinary(n // 2) + str(n % 2)
else:
return str(n)

Related

Why my return statement is not showing any output?

I was trying to solve the following problem: Draw a star pattern that increases in every step (1st step: 1 star, 2nd step: 2 stars). E.g.
*
**
I am not sure why my code is not showing any output when I am writing return? When I am writing print, it is giving me the star output but also giving me None. May I know why return or print are not working properly? I am using Python 3.7. My code is:
def string(inp):
for i in range (inp):
return i*"*"
print (string(5))
range starts at 0, and return terminates a function, so that means string will always return an empty string.
Here's one possible option for getting your expected result:
def stars(n):
for i in range(1, n+1): # Add one to start and stop
print(i * "*") # Print inside the function
stars(2) # Don't print outside the function
Output:
*
**
If you need to print outside the function, you could use a generator:
def stars(n):
for i in range(1, n+1):
yield i * "*" # "yield" is like "return" but can be used more than once
for s in stars(2):
print(s) # Print each string that gets yielded
# Or print all at once, using the "splat" unpacking operator
print(*stars(5), sep='\n')
Using return won't print an output, use something like this:
def string(inp):
for i in range (inp):
print(i*"*")
string(5)
also this will only print 4, if you make it
for i in range(inp + 1):
It will work as intended,
hope this helps!
I will translate the code to plain English, as explicitly as I can:
Here are the rules that take a value `inp` and compute the `string` of that `inp`:
Letting `i` take on each integer value from 0 up to but not including `inp`:
We are done. The `string` of `inp` is equal to the string '*' repeated `i` times.
Compute the `string` of `5` and display it.
Hopefully the problem is evident: we can only be done with a task once, and i is equal to 0 at that point, so our computed value is an empty string.
When I am writing print, it is giving me the star output but also giving me None
From the described behaviour, I assume that you mean that you tried to replace the word return in your code with print, giving:
def string(inp):
for i in range (inp):
print(i*"*")
print (string(5))
That produces the triangle, of course, except that
Since i will be equal to 0 the first time through the loop, a blank line is printed; and since i will be equal to 4 the last time through the loop, there is no ***** line.
At the end, None is printed, as you describe. This happens because the value computed by string is the special value None, which is then printed because you asked for it to be printed (print(string(5))).
In Python, each call to a function will return a value when it returns, whether or not you use return and whether or not you specify a value to return. The default is this special None value, which is a unique object of its own type. It displays with the text None when printed, but is different from a string with that text (in the same way that the integer 5 is different from the string "5").
May I know why return or print are not working properly?
They are working exactly as designed. return specifies the result of calling the function, and can only happen once per function, and does not cause anything to be displayed. print displays what it is given.
If you wish to return multiple values from a call, then you need to work around that restriction - either by using a generator instead (as in #MadPhysicist's or #wjandrea's answers), or by using some single, structured datum that contains all those values (for example, a list, or a tuple).
A a re-entrant function that preserves state between calls is a generator. To make a generator function, change the keyword return to yield:
def string(n):
for i in range(n):
yield (i + 1) * '*'
Calling this version of string will return a generator that yields a new line of your desired output at each iteration.
To print:
for line in string(5):
print(line)
To print all at once:
print('\n'.join(string(5)))

Building IP addresses from string

Write a program that determines where to add periods to a decimal string so that the resulting string is a valid IP address. There may be more than one valid IP address corresponding to a string, in which case you should print all possibilities. For example, "19216811", two of the nine possible IP addresses include 192.169.1.1 and 19.216.81.1.
Below is my (incomplete) solution:
def valid_ips(string):
def is_valid_part(part):
return len(part) == 1 or (part[0] != 0 and int(part) <= 255)
def build_valid_ips(substring):
result = []
for i in range(1, min(4, len(substring))):
part = substring[:i]
if is_valid_part(part):
for sub in build_valid_ips(substring[i:]):
result.append(part + '.' + sub)
return result
return build_valid_ips(string)
This is a variant problem in the book I'm working out of, so I don't have a solution to look at. However, I have a couple of questions
This solution is incorrect, as it always returns an empty list but I'm not sure why. Seems like I'm handling the inductive step and base case just fine. Could someone point me in the right direction?
How can I do this better? I understand each recursive call generates a new list and multiple new strings which adds a ton of overhead, but how to avoid this?
Your function always returns an empty list because you never append anything to result in the bottom layer of recursion.
In build_valid_ips you only append to result when looping through values obtained from a recursive call to build_valid_ips, but that would only return values obtained by looping through further recursive calls to build_valid_ips. Somewhere the recursion has to stop, but at this level, nothing gets appended. As a result there's nothing to pass back up the recursion.
Try adding the lines
if is_valid_part(substring):
result.append(substring)
in build_valid_ips, just after the line result = []. You should then find that your code then returns a non-empty list.
However, the result is still not correct. Nowhere in your code do you enforce that there must be four parts to an IP address, so the code will generate incorrect output such as 1.9.2.1.6.8.1.1. I'll leave it up to you to modify your code to fix this.
As for how to improve the code, that's more a question for Code Review. For a small example such as yours, which will never run for very long, I wouldn't be too worried about generating too many lists and strings. Worry about these things only when the performance of your code becomes a problem.
Given that an IP has to contain four different parts, you can use recursion to generate a list of possibilities with groupings:
s = "19216811"
def ips(d, current = []):
if not d:
yield current
else:
for i in range(1, len(s)):
yield from ips(d[i:], current + [d[:i]])
final_ips = list(filter(lambda x:all(len(i) > 1 for i in x[:2]), [i for i in ips(s) if len(list(filter(None, i))) == 4]))
new_ips = ['.'.join(a) for i, a in enumerate(final_ips) if a not in final_ips[:i]]
Output:
['19.21.6.811', '19.21.68.11', '19.21.681.1', '19.216.8.11', '19.216.81.1', '19.2168.1.1', '192.16.8.11', '192.16.81.1', '192.168.1.1', '1921.68.1.1']

Count occurrences of a given character in a string using recursion

I have to make a function called countLetterString(char, str) where
I need to use recursion to find the amount of times the given character appears in the string.
My code so far looks like this.
def countLetterString(char, str):
if not str:
return 0
else:
return 1 + countLetterString(char, str[1:])
All this does is count how many characters are in the string but I can't seem to figure out how to split the string then see whether the character is the character split.
The first step is to break this problem into pieces:
1. How do I determine if a character is in a string?
If you are doing this recursively you need to check if the first character of the string.
2. How do I compare two characters?
Python has a == operator that determines whether or not two things are equivalent
3. What do I do after I know whether or not the first character of the string matches or not?
You need to move on to the remainder of the string, yet somehow maintain a count of the characters you have seen so far. This is normally very easy with a for-loop because you can just declare a variable outside of it, but recursively you have to pass the state of the program to each new function call.
Here is an example where I compute the length of a string recursively:
def length(s):
if not s: # test if there are no more characters in the string
return 0
else: # maintain a count by adding 1 each time you return
# get all but the first character using a slice
return 1 + length( s[1:] )
from this example, see if you can complete your problem. Yours will have a single additional step.
4. When do I stop recursing?
This is always a question when dealing with recursion, when do I need to stop recalling myself. See if you can figure this one out.
EDIT:
not s will test if s is empty, because in Python the empty string "" evaluates to False; and not False == True
First of all, you shouldn't use str as a variable name as it will mask the built-in str type. Use something like s or text instead.
The if str == 0: line will not do what you expect, the correct way to check if a string is empty is with if not str: or if len(str) == 0: (the first method is preferred). See this answer for more info.
So now you have the base case of the recursion figured out, so what is the "step". You will either want to return 1 + countLetterString(...) or 0 + countLetterString(...) where you are calling countLetterString() with one less character. You will use the 1 if the character you remove matches char, or 0 otherwise. For example you could check to see if the first character from s matches char using s[0] == char.
To remove a single character in the string you can use slicing, so for the string s you can get all characters but the first using s[1:], or all characters but the last using s[:-1]. Hope that is enough to get you started!
Reasoning about recursion requires breaking the problem into "regular" and "special" cases. What are the special cases here? Well, if the string is empty, then char certainly isn't in the string. Return 0 in that case.
Are there other special cases? Not really! If the string isn't empty, you can break it into its first character (the_string[0]) and all the rest (the_string[1:]). Then you can recursively count the number of character occurrences in the rest, and add 1 if the first character equals the char you're looking for.
I assume this is an assignment, so I won't write the code for you. It's not hard. Note that your if str == 0: won't work: that's testing whether str is the integer 0. if len(str) == 0: is a way that will work, and if str == "": is another. There are shorter ways, but at this point those are probably clearest.
First of all you I would suggest not using char or str. Str is a built function/type and while I don't believe char would give you any problems, it's a reserved word in many other languages. Second you can achieve the same functionality using count, as in :
letterstring="This is a string!"
letterstring.count("i")
which would give you the number of occurrences of i in the given string, in this case 3.
If you need to do it purely for speculation, the thing to remember with recursion is carrying some condition or counter over which each call and placing some kind of conditional within the code that will change it. For example:
def countToZero(count):
print(str(count))
if count > 0:
countToZero(count-1)
Keep it mind this is a very quick example, but as you can see on each call I print the current value and then the function calls itself again while decrementing the count. Once the count is no longer greater than 0 the function will end.
Knowing this you will want to keep track of you count, the index you are comparing in the string, the character you are searching for, and the string itself given your example. Without doing the code for you, I think that should at least give you a start.
You have to decide a base case first. The point where the recursion unwinds and returns.
In this case the the base case would be the point where there are no (further) instances of a particular character, say X, in the string. (if string.find(X) == -1: return count) and the function makes no further calls to itself and returns with the number of instances it found, while trusting its previous caller information.
Recursion means a function calling itself from within, therefore creating a stack(at least in Python) of calls and every call is an individual and has a specified purpose with no knowledge whatsoever of what happened before it was called, unless provided, to which it adds its own result and returns(not strictly speaking). And this information has to be supplied by its invoker, its parent, or can be done using global variables which is not advisable.
So in this case that information is how many instances of that particular character were found by the parent function in the first fraction of the string. The initial function call, made by us, also needs to be supplied that information, since we are the root of all function calls and have no idea(as we haven't treaded the string) of how many Xs are there we can safely tell the initial call that since I haven't gone through the string and haven't found any or zero/0 X therefore here's the string entire string and could you please tread the rest of it and find out how many X are in there. This 0 as a convenience could be the default argument of the function, or you have to supply the 0 every time you make the call.
When will the function call another function?
Recursion is breaking down the task into the most granular level(strictly speaking, maybe) and leave the rest to the (grand)child(ren). The most granular break down of this task would be finding a single instance of X and passing the rest of the string from the point, exclusive(point + 1) at which it occurred to the next call, and adding 1 to the count which its parent function supplied it with.
if not string.find(X) == -1:
string = string[string.find(X) + 1:]
return countLetterString(char, string, count = count + 1)`
Counting X in file through iteration/loop.
It would involve opening the file(TextFILE), then text = read(TextFile)ing it, text is a string. Then looping over each character (for char in text:) , remember granularity, and each time char (equals) == X, increment count by +=1. Before you run the loop specify that you never went through the string and therefore your count for the number X (in text) was = 0. (Sounds familiar?)
return count.
#This function will print the count using recursion.
def countrec(s, c, cnt = 0):
if len(s) == 0:
print(cnt)
return 0
if s[-1] == c:
countrec(s[0:-1], c, cnt+1)
else:
countrec(s[0:-1], c, cnt)
#Function call
countrec('foobar', 'o')
With an extra parameter, the same function can be implemented.
Woking function code:
def countLetterString(char, str, count = 0):
if len(str) == 0:
return count
if str[-1] == char:
return countLetterString(char, str[0:-1], count+1)
else:
return countLetterString(char, str[0:-1], count)
The below function signature accepts 1 more parameter - count.
(P.S : I was presented this question where the function signature was pre-defined; just had to complete the logic.)
Hereby, the code :
def count_occurrences(s, substr, count=0):
''' s - indicates the string,
output : Returns the count of occurrences of substr found in s
'''
len_s = len(s)
len_substr = len(substr)
if len_s == 0:
return count
if len_s < len_substr:
return count
if substr == s[0:len_substr]:
count += 1
count = count_occurrences(s[1:], substr, count) ## RECURSIVE CALL
return count
output behavior :
count_occurences("hishiihisha", "hi", 0) => 3
count_occurences("xxAbx", "xx") => 1 (not mandatory to pass the count , since it's a positional arg.)

print pattern recursion

I need to write a recursive function printPattern() that takes an integer n as a parameter and prints n star marks followed by n exclamation marks, all on one line. The function should not have any loops and should not use multiplication of strings. The printing of the characters should be done recursively only. The following are some examples of the behavior of the function:
>>>printPattern(3)
***!!!
>>>printPattern(10)
**********!!!!!!!!!!
This is what I have at the moment
def printPattern(n):
if n < 1:
pass
else:
return '*'*printPattern(n)+'!'*printPattern(n)
I know I am completely off, and this would be easier without recursion, but it is necessary for my assignment.
Q: What's printPattern(0)?
A: Nothing.
Q: What's printPattern(n), for n>=1?
A: *, then printPattern(n-1), then !.
Now you should be able to do it. Just remember to think recursively.
Recursion is based on two things:
a base case
a way to get an answer based off something closer to the base case, given something that's not the base case.
In your case, the simplest base case is probably 0 - which would print thing (the empty string). So printPattern(0) is ''.
So how do you get closer to 0 from your input? Well, probably by reducing it by 1.
So let's say that you are currently at n=5 and want to base your answer off something closer to the base case - you'd want to get the answer for n=5 from the one for n=4.
The output for n=5 is *****!!!!!.
The output for n=4 is ****!!!!.
How do you get from the output of n=4 to n=5? Well, you add a * on the front and a ! on the end.
So you could say that printPattern(5) is actually just '*' + printPattern(4) + '!'.
See where this is going?
Try this:
def printPattern(n):
if n <= 0:
return ''
return '*' + printPattern(n-1) + '!'
print printPattern(5)
> *****!!!!!

Failing to understand recursion

New to Python and trying to understand recursion. I'm trying to make a program that prints out the number of times string 'key' is found in string 'target' using a recursive function, as in Problem 1 of the MIT intro course problem set. I'm having a problem trying to figure out how the function will run. I've read the documentation and some tutorials on it, but does anyone have any tips on how to better comprehend recursion to help me fix this code?
from string import *
def countR(target,key):
numb = 0
if target.find(key) == -1:
print numb
else:
numb +=1
return countR(target[find(target,key):],key)
countR('ajdkhkfjsfkajslfajlfjsaiflaskfal','a')
By recursion you want to split the problem into smaller sub-problems that you can solve independently and then combine their solution together to get the final solution.
In your case you can split the task in two parts: Checking where (if) first occurence of key exists and then counting recursively for the rest.
Is there a key in there:
- No: Return 0.
- Yes: Remove key and say that the number of keys is 1 + number of key in the rest
In Code:
def countR(target,key):
if target.find(key) == -1:
return 0
else:
return 1+ countR(target[target.find(key)+len(key):],key)
Edit:
The following code then prints the desired result:
print(countR('ajdkhkfjsfkajslfajlfjsaiflaskfal','a'))
This is not how recursion works. numb is useless - every time you enter the recursion, numb is created again as 0, so it can only be 0 or 1 - never the actual result you seek.
Recursion works by finding the answer the a smaller problem, and using it to solve the big problem. In this case, you need to find the number of appearances of the key in a string that does not contain the first appearance, and add 1 to it.
Also, you need to actually advance the slice so the string you just found won't appear again.
from string import *
def countR(target,key):
if target.find(key) == -1:
return 0
else:
return 1+countR(target[target.find(key)+len(key):],key)
print(countR('ajdkhkfjsfkajslfajlfjsaiflaskfal','a'))
Most recursive functions that I've seen make a point of returning an interesting value upon which higher frames build. Your function doesn't do that, which is probably why it's confusing you. Here's a recursive function that gives you the factorial of an integer:
def factorial(n):
"""return the factorial of any positive integer n"""
if n > 1:
return n * factorial(n - 1)
else:
return 1 # Cheating a little bit by ignoring illegal values of n
The above function demonstrates what I'd call the "normal" kind of recursion – the value returned by inner frames is operated upon by outer frames.
Your function is a little unusual in that it:
Doesn't always return a value.
Outer frames don't do anything with the returned value of inner frames.
Let's see if we can refactor it to follow a more conventional recursion pattern. (Written as spoiler syntax so you can see if you can get it on your own, first):
def countR(target,key):
idx = target.find(key)`
if idx > -1:
return 1 + countR(target[idx + 1:], key)
else:
return 0
Here, countR adds 1 each time it finds a target, and then recurs upon the remainder of the string. If it doesn't find a match it still returns a value, but it does two critical things:
When added to outer frames, doesn't change the value.
Doesn't recur any further.
(OK, so the critical things are things it doesn't do. You get the picture.)
Meta/Edit: Despite this meta article it's apparently not possible to actually properly format code in spoiler text. So I'll leave it unformatted until that feature is fixed, or forever, whichever comes first.
If key is not found in target, print numb, else create a new string that starts after the the found occurrence (so cut away the beginning) and continue the search from there.

Categories