Explanation for reverse_string recursive function - python

No matter how many times I run it by Python visualizer, I can't figure out how this code works; can someone PLEASE tell me how the recursion of this following code works?
def reverse_strings(string):
if len(string) == 0: return ''
else: return reverse_strings(string[1:]) + string[0]
reverse_strings('hello')
I wrote it myself, and it works, but I have no idea how it works. I know return recursion works by running the "ello" into the recursive function, but I can't for the life of me understand how it's printing things backwards.

The concept of recursion is that you call a the same function until the base case is encountered. In your case, the base case is when len(string) == 0, where you return an empty string to the caller, which was a previous version of the same function reverse_strings, but with different parameters (usually a more "complex" function).
Suppose you have this simple string hi, your function would behave like this:
Check if the base case is reached, if yes, return an empty string, otherwise go to next statement. Since we don't have an empty string, we go to the next statement.
Next statement calls the same function reverse_strings, but with different parameters than when you call it the first time to run it; in fact, the first time you call it, you do something like this reverse_strings('hi'). In the else, you are calling the function with a smaller version of your string hi, observe in the following statement: return reverse_strings(string[1:]) + string[0] that string[1:] is just i. Now, basically you have return reverse_strings('i') + string[0]. Note that string[0] is H. Here, reverse_strings('i'), as I said above, you are calling your function again, but with a smaller version of your string i.
Now, we are inside another function call. The first statement if len(string) == 0: return '' is evaluated. Is it true? No, because len(string) is still different from 0. So we pass to the next statement else: return reverse_strings(string[1:]) + string[0]. Now, note that we are going to call the same function again. but with a smaller string, in this case, an empty string, since string[1:] of i is an empty string. So our call can be summarised like this return reverse_strings('') + i.
We are now in another "simplified version" of reverse_strings. The first statement is evaluated if len(string) == 0: return ''. Is it true? Yes, because, remember, our string is now an empty string. What happens now is that you return an empty string to the caller, which is the function in the point 3.
Now, we have just returned an empty string to the caller at point 3, so we have return '' + i. '' + i is nothing else than simply i, which you are going to return to the caller of this function at pointer 3, which is the function at point 2.
Now, you have just returned i to the caller, specifically you have just returned i to this statement return reverse_strings('i') + string[0], where string[0] is H and reverse_strings('i') is just i that you have just returned. So, now you have iH, and you have just reversed the string.

It uses slicing to concatenate the first letter onto the end, then pass the 2nd to remaining letters into the recursive function again.

string[1:] on the first call is ello string[0] is h:
2nd recursive call string[1:] -> llo string[0] -> e
3rd string[1:] ->lo string[0] -> l
4th string[1:] ->o string[0] -> l
5th string[1:] ->"" string[0] -> o
So reverse_strings(string[1:]) calls the function recursively moving across the string and string[0] concatenates each letter starting from the end which is what is returned at the end.
The graph below may help:

To really understand this, I would express it in a declarative, sort-of logical form.
Here's your code:
1: if len(string) == 0: return ''
2: else: return reverse_strings(string[1:]) + string[0]
I'll call the first element of a string (string[0]) its head and the remainder (string[1:]) its tail. If a string is only 1 character long, we consider its tail to be the empty string. In terms of that vocabulary, here are the rules for what it means to reverse a string:
The empty string reversed is the empty string.
Any other string reversed is the reversed version of its tail, followed by its head.
In the case of, for example, abcd, we apply rule 2 since rule 1 doesn't apply:
abcd reversed is bcd reversed, followed by a.
Ok, what's bcd reversed? Well, we can apply the same rule:
bcd reversed is cd reversed, followed by b.
and down the chain:
cd reversed is d reversed, followed by c,
d reversed is '' reversed, followed by d,
'' reversed is '', by rule 1, because it is the empty string.
Going back up this list, you get:
'' followed by d followed by c followed by b followed by a
which is dcba, which is what we wanted!
Wrapping your head around recursion isn't easy. Try to solve some other problems with it or do some exercises that require it; this kind of practice really helps understanding.

Related

How do I implement recursion to this python program

def recurse( aList ):
matches = [ match for match in action if "A" in match ]
uses = " ".join(matches)
return f"Answer: { aList.index( uses )"
This is the non recursive method. I just couldn't figure out how to implement recursion in regards of lists.
Output should be Answer: n uses.
Can anybody help.
Recursion is a bad fit for this problem in Python, because lists aren' really recursive data structures. But you could write the following:
def recurse(aList):
if not aList:
return 0
return ("A" in aList[0]) + recurse(aList[1:])
Nothing in an empty list, by definition, contains "A". Otherwise, determined if "A" is in the first element of the list, and add 1 or 0 as appropriate (remember, bools are ints in Python) to the number of matches in the rest of the list.
The recursive function should only deal with the count itself; let the caller of the recursive function put the count into a string:
print("Answer: {recurse(aList)} uses"}

Why the output is two string when I pass a one character string to a python function

I've created a function called swap for an experiment. The function is as below:
def swap(x):
return x[-1:] + x[1:-1] + x[0:1]
When I try to pass a string "a", the output is "aa". I am not sure how's that happen. Thanks in advance if someone knows the reason.
Your function returns a new string based on:
The last letter of your string (a)
everything after the first letter but before the last letter (empty in your case)
and the first letter of your string (a)
So because your last letter is your first letter, you get them twice.
To swap them correctly, you'll have to test for string length:
def swap(x):
if len(x) < 2:
return x
return x[-1] + x[1:-1] + x[0]
Now that you know that in the last line x is at least two characters long, you also don't need slicing for the first/last character and can use direct element access (x[0]/x[-1]).
Actually this is ok.
x[-1:] will return the last character, becuase -1 starts from the end
x[0:1] will return the first character from beginning
x[1:-1] is nothing in this case because you don't have the second character
Btw for swap use return x.reverse() or return x[::-1]

Difference between string.replace(c,'',1)) and string[1:]

So I am trying to trace a recursive function and I'm having difficulties tracing this:
I'm trying to trace a code on permutations but this confuses me:
# doesn't work
def permutations(string):
if len(string) == 1:
return string
recursive_perms = []
for c in string:
for perm in permutations(string[1:]):
recursive_perms.append(c+perm)
return set(recursive_perms)
# works
def permutations(string):
if len(string) == 1:
return string
recursive_perms = []
for c in string:
for perm in permutations(string.replace(c,'',1)):
recursive_perms.append(c+perm)
return set(recursive_perms)
I'm horrible at tracing recursion currently, and I don't know the difference between the first and second function but the 2nd one works first one doesn't. The difference is the replace. Whats the different between the replace and doing string[1:]? Is there anyway you could change the replace into string slicing?
str.replace(old, new[, count]) replaces old with new, optionally only for the first count instances
str[1:] returns a slice of str from the character at the second index until the last index, effectively returning the entire string except for it's first character.
What really happens when you call str[1:] is that you're calling str.__getitem__(slice(1, None))

string match algorithm code for advice

Debugging the following problem, post problem and code reference I am debugging. My question is, I think this if condition check if not necessary, and could be removed safely? If I am wrong, please feel free to correct me. Thanks.
if len(first) > 1 and first[0] == '*' and len(second) == 0:
return False
Given two strings where first string may contain wild card characters and second string is a normal string. Write a function that returns true if the two strings match. The following are allowed wild card characters in first string.
* --> Matches with 0 or more instances of any character or set of characters.
? --> Matches with any one character.
For example, g*ks matches with geeks match. And string ge?ks* matches with geeksforgeeks (note * at the end of first string). But g*k doesn’t match with gee as character k is not present in second string.
# Python program to match wild card characters
# The main function that checks if two given strings match.
# The first string may contain wildcard characters
def match(first, second):
# If we reach at the end of both strings, we are done
if len(first) == 0 and len(second) == 0:
return True
# Make sure that the characters after '*' are present
# in second string. This function assumes that the first
# string will not contain two consecutive '*'
if len(first) > 1 and first[0] == '*' and len(second) == 0:
return False
# If the first string contains '?', or current characters
# of both strings match
if (len(first) > 1 and first[0] == '?') or (len(first) != 0
and len(second) !=0 and first[0] == second[0]):
return match(first[1:],second[1:]);
# If there is *, then there are two possibilities
# a) We consider current character of second string
# b) We ignore current character of second string.
if len(first) !=0 and first[0] == '*':
return match(first[1:],second) or match(first,second[1:])
return False
thanks in advance,
Lin
That if statement is critical to the proper operation of the function. Removing it will have disastrous consequences.
For example, assume that first="*a" and second="". In other words, the function was called as match("*a",""). Then the if statement will cause the function to return False (which is correct since there is no a in second). Without the if statement, the code will proceed to the line
return match(first[1:],second) or match(first,second[1:])
The call match(first[1:],second) will evaluate to match("a","") which will return False. But when the code calls match(first,second[1:]), the call is equivalent to match("*a",""), and the result is infinite recursion.

Using python 3 for recursive Boolean check if a list is sorted

I am trying to write a recursive function that does a Boolean check if a list is sorted. return true if list is sorted and false if not sorted. So far I am trying to understand if I have the 'base case' correct (ie, my first 'if' statement):
def isSorted(L, i=[]):
if L[i] > L[i + 1]:
return false
else:
return true
Am I correct with my initial if "L[i] > L[i + 1]:" as base case for recursion?
Assuming my 'base case' is correct I am not sure how to recursively determine if the list is sorted in non-descending order.
here is what I came up with. I designate the default list to 0; first check to see if first item is the last item. if not, should check each item until it reaches the end of the list.
def isSorted(L):
# Base case
if len(L) == 1:
return True
return L[0] <= L[1] and isSorted(L[1:])
This is how I would start. Write a function with the following signature:
function isSorted(currentIndex, collection)
Inside the function, check to see if currentIndex is at the end of the collection. If it is, return true.
Next, check to see if collection[index] and collection[index+1] are sorted correctly.
If they aren't, return false
If they are, return isSorted(currentIndex+1, collection)
Warning: this is a horrible use for recursion
No, the base case will be when you reach the end of the list, in which case you return true.
Otherwise, if the two elements you are looking at are out of order return false.
Otherwise, return the result of a recursive call on the next elements down the list.
I agree with #MStodd: recursion is not the way to solve this problem in Python. For a very long list, Python may overflow its stack! But for short lists it should be okay, and if your teacher gave you this problem, you need to do it this way.
Here is how you should think about this problem. Each recursive call you should do one of three things: 0) return False because you have found that the list is not sorted; 1) return True because you have reached your base case; 2) break the work down and make the remaining problem smaller somehow, until you reach your base case. The base case is the case where the work cannot be broken down any further.
Here is a broad outline:
def recursive_check(lst, i):
# check at the current position "i" in list
# if check at current position fails, return False
# update current position i
# if i is at the end of the string, and we cannot move it any more, we are done checking; return true
# else, if i is not at the end of the string yet, return the value returned by a recursive call to this function
For example, here is a function that checks to see if there is a character '#' in the string. It should return True if there is no # anywhere in the string.
def at_check(s, i):
if s[i] == '#':
return False
i += 1
if i >= len(s):
return True
else:
return at_check(s, i)
I wrote the above exactly like the outline I gave above. Here is a slightly shorter version that does the same things, but not in exactly the same order.
def at_check(s, i=0):
if i >= len(s):
return True
if s[i] == '#':
return False
return at_check(s, i+1)
EDIT: notice that I put i=0 in the arguments to at_check(). This means that the "default" value of i will be 0. The person calling this function can just call at_check(some_string) and not explicitly pass in a 0 for the first call; the default argument will provide that first 0 argument.
The only time we really need to add one to i is when we are recursively calling the function. The part where we add 1 is the important "breaking down the work" part. The part of the string we haven't checked yet is the part after i, and that part gets smaller with each call. I don't know if you have learned about "slicing" yet, but we could use "slicing" to actually make the string get smaller and smaller with each call. Here is a version that works that way; ignore it if you don't know slicing yet.
def at_check(s):
if s == '': # empty string
return True
if s[-1] == '#': # is last character '#'?
return False
return at_check(s[:-1]) # recursive call with string shortened by 1
In this version, an empty string is the basis case. An empty string does not contain #, so we return True. Then if the last character is # we can return False; but otherwise we chop off the last character and recursively call the function. Here, we break the work down by literally making the string get shorter and shorter until we are done. But adding 1 to the index variable, and moving the index through the string, would be the same thing.
Study these examples, until you get the idea of using recursion to break down the work and make some progress on each recursive call. Then see if you can figure out how to apply this idea to the problem of finding whether a list is sorted.
Good luck!

Categories

Resources