Basic recursion on string? - python

I want to have a program that prints me a word in this way only by recursion and if-else clauses:
P
Py
Pyt
Pyth
Pytho
Python
Why does following code not work? It gives me an error of maximum recursion depth exceeded.
def oneToAll (word, x):
if -x < 0:
print(word[:-x])
oneToAll(word, x+1)
else:
return
wordOutside = "Python"
oneToAll(wordOutside, len(wordOutside))

def oneToAll (word, x):
if -x < 0:
print(word[:-x])
oneToAll(word, x-1)
elif x == 0:
print(word)
else:
return
wordOutside = "Python"
oneToAll(wordOutside, len(wordOutside))
This seems to work. Note that I've now recursed using x-1 instead of x+1 because you want x to always be working its way toward 0.
Implementing this way, you have to handle the special case where x == 0. In that case, you want to print the entire string, not word[:0] (which is always an empty string). Also note that I didn't recurse further from the 0 branch. This is because at this point, you're done. You can actually remove the else clause entirely (give it a try!).

I may be missing something, but you could achieve the same thing like this:
def one_to_all(w):
if w:
one_to_all(w[:-1])
print w
one_to_all('Python')
Your code doesn't work because (i) you add 1 to x instead of subtracting 1 and (ii) when x reaches zero, word[:-x] is an empty string, so you need to deal with that case separately.

Try this code with intuitive index of "word"
def oneToAll(word, x):
if x > 1:
print (word[0:len(word) - x])
oneToAll(word, x - 1)
elif x == 1:
print (word)
wordOutside = "Python"
oneToAll(wordOutside, len(wordOutside))

Related

is there a simpler way to complete the following exercise? I am adding elements to a string, depending on three conditions

From Google Python Class
D. Verbing :
Given a string, if its length is at least 3, add 'ing' to its end.
Unless it already ends in 'ing', in which case add 'ly' instead.
If the string length is less than 3, leave it unchanged.
Return the resulting string.
def verbing(s):
if len(s) < 3:
return s
if len(s) >= 3 and s[-3:] == 'ing':
s = s + 'ly'
return s
elif s[:-3] != 'ing':
s = s + 'ing'
return s
Test Cases
print 'verbing'
test(verbing('hail'), 'hailing')
test(verbing('runt'), 'runting')
test(verbing('swiming'), 'swimingly')
test(verbing('do'), 'do')
test(verbing('hi'), 'hi')
You can use str.endswith:
test_cases = ["ing", "webbing", "xy", "house"]
def verbing(s):
return s if len(s) < 3 else (s + "ly" if s.endswith("ing") else s + "ing")
for t in test_cases:
print(t, verbing(t))
Prints:
ing ingly
webbing webbingly
xy xy
house houseing
Your control flow statements (if/elif/else) all end with return s, so you could restructure things to eliminate the redundant return s statements:
def verbing(s):
if len(s) >= 3:
if s[-3:] == 'ing':
s = s + 'ly'
elif s[:-3] != 'ing':
s = s + 'ing'
return s
This also eliminates the if len(s) < 3 line, since if len(s) isn't greater than or equal to 3, that must mean it is less than 3, so there isn't much of a point in checking for that explicitly.
Similarly, since the if s[-3:] == 'ing' line asks "does this end in -ing? yes or no?", if the answer is not "yes", it must be "no" (or in this case, False). So the elif statement can be replaced with a simpler and more efficient else (more efficient since it's not checking & evaluating another condition). You can also shorten s = s + something statements to s += something, which is a bit shorter and nicer to read:
def verbing(s):
if len(s) >= 3:
if s[-3:] == 'ing':
s += 'ly'
else:
s += 'ing'
return s
Finally, there's a shorter way to write simple if/else statements which in other languages is known as the ternary operator, which applied here would look something like this:
def verbing(s):
if len(s) >= 3:
# the parentheses are not needed but do
# help make it more clear what's going on
s += ('ly' if s[-3:] == 'ing' else 'ing')
return s
This ('ly' if s[-3:] == 'ing' else 'ing') statement gets evaluated in the same way as the previous if/else statement, just written in a different way. It can be read as "this statement should be equal to 'ly' if the string ends in 'ing'; otherwise, this statement should be equal to 'ing'." The value of that statement is what will get tacked onto the end of the string s.
Ultimately, I think the code you began with is a good place to start, since it does in fact work. And you're right to want to review that code to see if there are places where it could be cleaner, shorter, and/or more efficient. This is roughly how I personally go about these sorts of things and I hope this may help you in the process of improving and refactoring the code you write in future. Good luck and have fun!
Here's what I could come up with on a short notice:
def verbing(string: str) -> str:
if len(string) >= 3:
if not string.endswith("ing"):
string += "ing"
else:
string += "ly"
return string
Hope that helps.
There are many different ways to solve this problem. I think that first you need to ask yourself why your solution isn't good enough. Maybe if you will run import this you will understand better how code in python should look like and what are the values that you should follow.
Although this pattern is way to much for this small problem, for education purpose I will intrude another pattern that can be handy if the problem should be address from the scale point of view.
def cond_ing(st):
return st[-3:] != "ing"
def add_ing(st):
return st + "ing"
def cond_ly(st):
return st[-3:] == "ing"
def add_ly(st):
return st + "ly"
d = {
cond_ing: add_ing,
cond_ly: add_ly
}
now you can run a simple for loop and every one can just add which condition that they would like. something like:
for s in tests:
if len(s) <= 3:
print(s)
continue
for con in d:
if con(s):
print(d[con](s))

Determining validity if sum divisible by 10

Outline:
Find out if id is acceptable. Acceptable parameters is the sum of the
digits for each part of the id. If each sum is evenly divisible by 10
then the function returns the string "Acceptable", otherwise it
returns the string "Unacceptable".
Example:
isValid('123-12-134') → 'Unacceptable'
isValid('550-55-055') → 'Acceptable'
isValid('123-55-055') → 'Unacceptable'
I've tried converting the entire string into an int, but get some differing results in determining divisible by 10.
My attempted code is:
def isValid(id) :
id=id.replace('-','0')
id=int(id)
if id % 10==0:
return "Valid"
else:
return "Invalid"
Thanks in advance!
You might as well return boolean variables and just compare the output to determine what to print:
def summation(item):
return sum([int(i) for i in item])
def isValid(id_) :
id_part = id_.split('-')
result = [summation(item) % 10 == 0 for item in id_part]
return all(result)
Essentially this loops through all the characters in the split string and determines their sum - 3 sums per provided id.
Then we convert the summed list to a boolean list using your condition of x%10 == 0.
Finally we look at all() the elements of this boolean list to determine if it all True or contains a False.
If all are True then the return of isValid(id_) is True else it is False.
Usage:
ids = ['123-12-134', '550-55-055', '123-55-055']
for id_ in ids:
validity = isValid(id_)
print("Acceptable") if validity else print("Unacceptable")
Output:
Unacceptable
Acceptable
Unacceptable
you mean like this?
sentence = "123-123-123"
a = sum(int(x) for x in sentence if x.isdigit())
Hope this code can help you.
Found on this answer
you mean like this?
sentence = "123-123-123"
a = sum(int(x) for x in sentence if x.isdigit())
return a % 10 == 0
Hope this code can help you.
Found on this answer
We want to short-circuit the 'Unacceptable'.
def isValid(ID):
s = 0
for x in ID:
if x.isdigit():
s += int(x)
else:
if s % 10 == 0:
s = 0
else:
return 'Unacceptable'
return 'Acceptable' if s%10 == 0 else 'Unacceptable'
The solution requires splitting the string into parts using hyphens as separators, which are tested to ensure that the sum of each part's characters is a multiple of 10. The test fails if any of the parts are not a multiple of ten, so each part must be greater than or equal to ten. If any part fails, the string fails, so, there is no need to continue testing if a failed part is found. Acceptable must be returned if the string passes, or Unacceptable if it fails.
This single function solution is easy to read:
def teststring(test):
for part in test.split('-'):
part_failed = int(part)<10
if not part_failed:
sum_chars = 0
for char in part:
sum_chars += int(char)
part_failed = ((sum_chars % 10) != 0)
if part_failed: break
return 'Acceptable' if not part_failed else 'Unacceptable'
This solution uses list comprehension in two functions:
def testpart_comprehended(part):
return ((int(part)>=10) and ((sum(int(char) for char in part) % 10) == 0))
def acceptable_comprehended(test):
return 'Acceptable' if all(testpart_comprehended(part) for part in test.split("-")) else 'Unacceptable'
This solution uses list comprehension in one function:
def all_comprehended(test):
return 'Acceptable' if all(((int(part)>=10) and ((sum(int(char) for char in part) % 10) == 0)) for part in test.split("-")) else 'Unacceptable'
These answers are all too understandable. Please use
isValid = lambda x: (any(sum(map(int, s)) % 10 for s in x.split('-'))
* 'un' + 'acceptable').title()
Unacceptable
for example
>>> isValid('123-123')
'Unacceptable'
>>> isValid('123-127')
'Unacceptable'
>>> isValid('127-127')
'Acceptable'

recursive function python 3 'maximum recursion depth exceeded'

I am creating a collatz sequence with a recursive function below:
def collatz(n):
if n%2 == 0:
return int(n/2)
else:
return int((3 * n)/2)
From what I understand, a recursive function is a function that basically calls itself. Below I have attempted creating the recursive function with the following:
def collatz(x):
if x == 1:
"Done"
print(x)
x = collatz(x)
return(x)
Where essentially the variable x continues to get passed into the collatz function I defined until it gets to 1. However, every time I run the recursive function it prints 'x' repeatedly and then I get the
collatz(3)
'RecursionError: maximum recursion depth exceeded in comparison'
Which I understand is an infinite loop essentially. I thought by reassigning it to x to the results of the first collatz() it would return the new value and continue till it hit '1' but I can't seem to quite get there.
Any help/tips/advice would be great! Thanks!
Recursive functions have what's known as a "base case" and what's known as a "recursive case." The base case is when you should stop recursing and return an answer.
In this case, the base case is when x==1
def collatz(x):
if x == 1:
return x
and the recursive case is the rest of the time
# continuing from above
else:
if n % 2 == 0:
return collatz(int(n//2))
else:
return collatz(n*3 / 2) # sicut. Note that the collatz sequence
# uses 3n+1 here, not 3n/2 as in the question
N.B. that I change the effective value of x in the next loop through collatz before returning the result of that new call. If you don't, and simply return collatz(x), you'll never reach your base case and recurse forever.
#Roee Gavirel
Here is the final answer based on his answer above:
def collatz(x):
if x == 1:
"Done"
elif x%2 == 0:
x = int(x/2)
print(x)
collatz(x)
else:
x = int((3*x)+1)
print(x)
collatz(x)
collatz(3)
Thanks for all the help!
You show two different implementations of the same function collatz, while you need to combine them.
def collatz(n):
if x == 1:
"Done"
print(x)
if n%2 == 0:
collatz(int(n/2))
else:
collatz(int((3 * n)/2))

More than one if-else in single line, how to interpret them?

Well I certainly Understand if-else that are return in single line like
return 0 if x==y else 1
Which translate to
if x==y:
return 0
else:
return 1
I am confused about those statements where if-else occurs multiple time in one line like
def cmp(x, y):
return 0 if x == y else 1 if x > y else -1
How to interpret and understand if-else statements, that are written in single line.
Introducing parentheses makes it easier to understand.
0 if x == y else 1 if x > y else -1
must be parsed as
0 if x == y else (1 if x > y else -1)
it's nested else-if ,for clarity it can be seen as this
if x == y:
return 0
else:
if x > y:
return 1
else:
return -1
and it would be great if the code is clear and understandable in less possible efforts
So later, what if you want to add one more case in lengthy conditional statements then it can be issue so better option is to use elif ladder like this
def _comp(total):
if total>90:
return 'Python lover'
elif total>80 and total<=89:
return 'Friend of python'
# elif total>50 and total<=79 added later easily
# return 'you like python' added later easily
else:
return 'python is waiting for you'

What does "equals to negative 1" mean in Python?

I'm trying to understand a piece of code that searches for a string inside a text file. What does it mean? Is it like "False"?
if x.find('string1') != -1:
if x.find('string2') == -1 and x.find('string3') == -1:
return file
break
From the str.find() method documentation:
Return -1 if sub is not found.
So the first if condition tests if string1 is found in x; if it is, a value other than -1 would be returned. The second if condition tests if two strings are not present in x (because only then -1 is returned for both str.find() calls).
It really should use a membership test (the in operator) instead:
if 'string1' in x and 'string2' not in x and 'string3' not in x:
return file
The break after the return is never reached.

Categories