Python beginner recursion - python

I am trying to get a simple function which takes n and prints
If n > 0:
print((n*'*')+(n*'!'), end=' ')
and trying to get the same solution but recursively. I am a beginner to recursion, and often I get the "higher level of thinking", but I am having trouble understanding the code that must follow.
My base case is that when n is 0 it prints nothing. When n is more than 1 it will print n copies of * + n copies of!
def repeat(n):
if n <= 0:
pass
else:
repeat(n-1)
print((n*'*')+(n*'!'), end=' ')
right now it prints n, and then n-1 successively until 0. I have tried breaking it up into two print statements and using more than one recursion .. but it becomes a messy pattern.
I am also not allowed to use loops. This one is driving me insane; I have come up with several solutions to it besides the easy one line statement, but none that use recursion.

It's simpler if you build and return a string and print it outside of the function, like this:
def printPattern(n):
if n <= 0:
return ''
return '*' + printPattern(n-1) + '!'
Or as a one-liner:
def printPattern(n):
return '*' + printPattern(n-1) + '!' if n > 0 else ''
Either way, this works:
print printPattern(5)
> *****!!!!!

Assume you have a solution for n - 1. Prepend * and append !.
def repeat(n):
if n > 0:
print("*", end=" ")
repeat(n - 1)
print("!", end=" ")

The following does what you appear to want.
def repeat(n):
def stars(n):
return '*'+stars(n-1)+'!' if n > 0 else ''
print stars(n)
For example, repeat(5) prints *****!!!!! and repeat(8) prints
********!!!!!!!!.

I don't actually know what you're asking... If there's a more efficient or better way of doing this? This would be quite obvious:
def repeat(n):
if n >= 0:
print((n*'*')+(n*'!'), end=' ')
return repeat(n-1)

I would use two strings here, and return a concatenated string of those two strings when n<=0 and use return instead of printing inside function:
def repeat(n, strs1="", strs2=""): # The Default value of strings is ""
if n <= 0:
return strs1 + strs2 # if n<=0 then concatenate the two strings and return them
else:
strs1 += "*" # Add * to strs1
strs2 += "!" # Add ! to strs2
return repeat(n-1, strs1, strs2) # Pass n-1, as well as the two strings to a recursive call
print(repeat(5))
print(repeat(3))
Output:
*****!!!!!
***!!!

Related

How to *return* Binary of decimal in recursion code Python

Learning Recursion. I was able to write Python code to print binary number using recursion but couldn't figure out how to return this binary number. I am only getting the first mod value when I return, probably because, as I understand, the stack folds back to the beginning by the time it can return. (Hope this is not wrong). I would greatly appreciate if you could not only provide your answer to get the function to return the result but also explain how it works.
def binary(n):
if n == 0:
return
else:
binary (n//2)
print (n%2,end="")
binary(233)
Thank you
Arun
To return a value, you need to use return instead of print.
But also pay attention to this:
When using return you need to accumulate the binary digits in a string
The base case is not correct: 0 does not translate to an empty string when that is the original value of n (then you want to get 0 back). It only should be an empty string if you are in a recursive call. The way to solve this, is to stop the recursion one step earlier, i.e. when n < 2.
Here is how that works out:
def binary(n):
if n < 2:
return str(n)
else:
return binary(n // 2) + str(n % 2)
Call as:
print(binary(13))
def binary(n):
if n == 0:
return ""
else:
i = n % 2
print(i, end="")
return binary(n // 2) + str(i)
x = binary(233)
print() # seperate the print's in binary from this print
print(x)
To actually return something from the function you need to put something into the return statement. Here for each call of binary(n) i'm returning the number obtained by your operation as a string so I can concatenate it together and return it at the end.

sum of numbers/extact digits

I am new to coding and try to extract and print the none digits. I've written 2 different codes but cannot combine them. I would appreciate some advices. (i tried using *args but didn't work)
def SumOfDigits(str1):
sum_digit = 0
for x in str1:
if x.isdigit():
z = int(x)
sum_digit += z
print("The sum of digits operation is", sum_digit, end=".")
return
def SumOfDigits(input):
valids = []
for character in input:
if character.isalpha():
valids.append(character)
print("The extracted non-digits are:", ''.join(valids))
return
El. Nik, i believe that those 2 function you not be merged as they are doing different behavior, which lead to a more complex function, that might get a bit confusing.
Anyway, what you want is to merge your two for loop into a single one. Since str.isalpha matches do not collide with str.isdigit ones, you can safely use a if statement followed by an elif to check every charater and apply the wanted behavior.
Then, you simply return the 2 results as a tuple.
def digit_extraction(string):
sum_digits = 0
extracted_alphas = ""
for char in string:
if char.isdigit():
sum_digits += int(char)
elif char.isalpha():
extracted_alphas += char
return sum_digits, extracted_alphas
Here is a quick example:
>>> digit_extraction("1a2b3c4d5e6f7g8h9i")
(45, 'abcdefghi')
If you dont know how multiple return value works in python, i'd suggest to check the following tutorial:
https://datagy.io/python-return-multiple-values/
To get into something more advanced, separating the 2 function would allow for writting something considered as more pythonic:
def sum_of_digits(string):
return sum(int(c) for c in string if c.isalpha())
and
def extract_alphas(string):
return ''.join(filter(str.isalpha, c))

Python need help figuring inclusive

Full disclosure, I am in school and I missed a problem on codingbat assignment 2 weeks ago, I am hoping I can get some direction here so that I can learn for the future
my problem was
Given a string and an int n, return a string made of the first n characters of the string, followed by the first n-1 characters of the string, inclusive (i.e. 0 <= n and n <= len(str)).
d_2('ydu', 2) → 'ydy'
d_2('yoda', 3) → 'yod'
d_2('yoda', 1) → '1'
The farthest I could get was:
def d_2(string, n):
string = string[:-n:]
return string
this would return 2 right answers
if I did
def d_2(string, n):
string = string[:-n:10]
return string
it would return 3 right answers.
I am sure it is a very simple thing, but my brain just is not picking it out, any direction
You can try making a loop to construct the string a = string[:n-1] + string[:n-2] + string[:n-3] .... until n is equal to 0.
def echo_first(string, n):
a=''
while n > 0:
a += string[:n]
n -= 1
return a
You could try with Recursive Functions to call the function itself until n==1:
def echo_first(string, n):
return string[:1] if n==1 else string[:n]+echo_first(string, n-1)

Longest string in alphabetic order

This code works fine for all the strings, except for the ones where the last char is needed.
s='abcdefghijklmnopqrstuvwxyz'
sub =''
test =s[0]
for n in range(len(s)-1):
if len(test) > len(sub):
sub = test
if s[n] >= s[n-1]:
test += s[n]
else:
test = s[n]
print 'Longest substring in alphabetic order is: ' + str(sub)
How do you suggest a possibility for doing this?
Thank you in advance guys!
PS:
Thanks for the answers so far. The problem is that, no matter which range I type, the sub variable, which I will print, doesn't get all the chars I want. The loop finishes before :\ Maybe it's a problem with the program itself.
Any extra tips? :)
Your problem is with range(len(s)-1). Range generates a list up to its upper limit parameter value-1 so you don't need to subtract1 to len(s), use:
range(len(s))
From https://docs.python.org/2/library/functions.html#range
range(stop)
range(start, stop[, step])
This is a versatile function to create lists containing arithmetic progressions. It is most often used in for loops. The arguments must
be plain integers. If the step argument is omitted, it defaults to 1.
If the start argument is omitted, it defaults to 0. The full form
returns a list of plain integers [start, start + step, start + 2 *
step, ...]. If step is positive, the last element is the largest start
+ i * step less than stop; if step is negative, the last element is the smallest start + i * step greater than stop. step must not be zero
On the other hand, you are labeling your question as python2.7 so I assume you are using 2.7. If that is the case, it is more efficient to use xrange instead range because that way you will use an iterator instead generating a list.
EDIT
From the comments to this question, you can change your code to:
s='caabcdab'
sub =''
test =s[0]
for i in range(1,len(s)+1):
n = i%len(s)
if len(test) > len(sub):
sub = test
if i >= len(s):
break
if s[n] >= s[n-1]:
test += s[n]
else:
test = s[n]
print 'Logest substring in alphabetic order is: ' + str(sub)
you enemurate instead of range:
s='abcdefghijklmnopqrstuvwxyz'
sub =''
test =s[0]
for n,value in enumerate(s):
if len(test) > len(sub):
sub = test
if value >= s[n-1]:
test += s[n]
else:
test = s[n]
You could do use the following code:
s = 'abcdefgahijkblmnopqrstcuvwxyz'
sub = ''
test = s[0]
for index, character in enumerate(s):
if index > 0:
if character > s[index - 1]:
test += character
else:
test = character
if len(test) > len(sub):
sub = test
print 'Longest substring in alphabetic order is: ' + str(sub)
A few pointers too.
Python strings are iterable. i.e you can loop through them.
Use enumerate when you want the index of the list while iterating it.

Reverse a string without using reversed() or [::-1]?

I came across a strange Codecademy exercise that required a function that would take a string as input and return it in reverse order. The only problem was you could not use the reversed method or the common answer here on stackoverflow, [::-1].
Obviously in the real world of programming, one would most likely go with the extended slice method, or even using the reversed function but perhaps there is some case where this would not work?
I present a solution below in Q&A style, in case it is helpful for people in the future.
You can also do it with recursion:
def reverse(text):
if len(text) <= 1:
return text
return reverse(text[1:]) + text[0]
And a simple example for the string hello:
reverse(hello)
= reverse(ello) + h # The recursive step
= reverse(llo) + e + h
= reverse(lo) + l + e + h
= reverse(o) + l + l + e + h # Base case
= o + l + l + e + h
= olleh
Just another option:
from collections import deque
def reverse(iterable):
d = deque()
d.extendleft(iterable)
return ''.join(d)
Use reversed range:
def reverse(strs):
for i in xrange(len(strs)-1, -1, -1):
yield strs[i]
...
>>> ''.join(reverse('hello'))
'olleh'
xrange or range with -1 step would return items in reversed order, so we need to iterate from len(string)-1 to -1(exclusive) and fetch items from the string one by one.
>>> list(xrange(len(strs) -1, -1 , -1))
[4, 3, 2, 1, 0] #iterate over these indexes and fetch the items from the string
One-liner:
def reverse(strs):
return ''.join([strs[i] for i in xrange(len(strs)-1, -1, -1)])
...
>>> reverse('hello')
'olleh'
EDIT
Recent activity on this question caused me to look back and change my solution to a quick one-liner using a generator:
rev = ''.join([text[len(text) - count] for count in xrange(1,len(text)+1)])
Although obviously there are some better answers here like a negative step in the range or xrange function. The following is my original solution:
Here is my solution, I'll explain it step by step
def reverse(text):
lst = []
count = 1
for i in range(0,len(text)):
lst.append(text[len(text)-count])
count += 1
lst = ''.join(lst)
return lst
print reverse('hello')
First, we have to pass a parameter to the function, in this case text.
Next, I set an empty list, named lst to use later. (I actually didn't know I'd need the list until I got to the for loop, you'll see why it's necessary in a second.)
The count variable will make sense once I get into the for loop
So let's take a look at a basic version of what we are trying to accomplish:
It makes sense that appending the last character to the list would start the reverse order. For example:
>>lst = []
>>word = 'foo'
>>lst.append(word[2])
>>print lst
['o']
But in order to continue reversing the order, we need to then append word[1] and then word[0]:
>>lst.append(word[2])
>>lst.append(word[1])
>>lst.append(word[0])
>>print lst
['o','o','f']
This is great, we now have a list that has our original word in reverse order and it can be converted back into a string by using .join(). But there's a problem. This works for the word foo, it even works for any word that has a length of 3 characters. But what about a word with 5 characters? Or 10 characters? Now it won't work. What if there was a way we could dynamically change the index we append so that any word will be returned in reverse order?
Enter for loop.
for i in range(0,len(text)):
lst.append(text[len(text)-count])
count += 1
First off, it is necessary to use in range() rather than just in, because we need to iterate through the characters in the word, but we also need to pull the index value of the word so that we change the order.
The first part of the body of our for loop should look familiar. Its very similar to
>>lst.append(word[..index..])
In fact, the base concept of it is exactly the same:
>>lst.append(text[..index..])
So what's all the stuff in the middle doing?
Well, we need to first append the index of the last letter to our list, which is the length of the word, text, -1. From now on we'll refer to it as l(t) -1
>>lst.append(text[len(text)-1])
That alone will always get the last letter of our word, and append it to lst, regardless of the length of the word. But now that we have the last letter, which is l(t) - 1, we need the second to last letter, which is l(t) - 2, and so on, until there are no more characters to append to the list. Remember our count variable from above? That will come in handy. By using a for loop, we can increment the value of count by 1 through each iteration, so that the value we subtract by increases, until the for loop has iterated through the entire word:
>>for i in range(0,len(text)):
..
.. lst.append(text[len(text)-count])
.. count += 1
Now that we have the heart of our function, let's look at what we have so far:
def reverse(text):
lst = []
count = 1
for i in range(0,len(text)):
lst.append(text[len(text)-count])
count += 1
We're almost done! Right now, if we were to call our function with the word 'hello', we would get a list that looks like:
['o','l','l','e','h']
We don't want a list, we want a string. We can use .join for that:
def reverse(text):
lst = []
count = 1
for i in range(0,len(text)):
lst.append(text[len(text)-count])
count += 1
lst = ''.join(lst) # join the letters together without a space
return lst
And that's it. If we call the word 'hello' on reverse(), we'd get this:
>>print reverse('hello')
olleh
Obviously, this is way more code than is necessary in a real life situation. Using the reversed function or extended slice would be the optimal way to accomplish this task, but maybe there is some instance when it would not work, and you would need this. Either way, I figured I'd share it for anyone who would be interested.
If you guys have any other ideas, I'd love to hear them!
Only been coding Python for a few days, but I feel like this was a fairly clean solution. Create an empty list, loop through each letter in the string and append it to the front of the list, return the joined list as a string.
def reverse(text):
backwardstext = []
for letter in text:
backwardstext.insert(0, letter)
return ''.join(backwardstext)
I used this:
def reverse(text):
s=""
l=len(text)
for i in range(l):
s+=text[l-1-i]
return s
Inspired by Jon's answer, how about this one
word = 'hello'
q = deque(word)
''.join(q.pop() for _ in range(len(word)))
This is a very interesting question, I will like to offer a simple one
liner answer:
>>> S='abcdefg'
>>> ''.join(item[1] for item in sorted(enumerate(S), reverse=True))
'gfedcba'
Brief explanation:
enumerate() returns [(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd'), (4, 'e'), (5, 'f'), (6, 'g')]. The indices and the values.
To reverse the values, just reverse sort it by sorted().
Finally, just put it together back to a str
I created different versions of how to reverse a string in python in my repo:
https://github.com/fedmich/Python-Codes/tree/master/Reverse%20a%20String
You can do it by using list-comprehension or lambda technique:
# Reverse a string without using reverse() function
s = 'Federico';
li = list( s ) #convert string to list
ret = [ li[i-1] for i in xrange(len(li),0,-1) ] #1 liner lambda
print ( "".join( ret ) )
or by doing a backward for loop
# Reverse a string without using reverse() function
s = 'Federico';
r = []
length = len(s)
for i in xrange(length,0,-1):
r.append( s[ i - 1] )
print ( "".join(r) )
reduce(lambda x, y : y + x, "hello world")
A golfed version: r=lambda x:"".join(x[i] for i in range(len(x-1),-1,-1)).
i just solved this in code academy and was checking my answers and ran across this list. so with a very limited understanding of python i just did this and it seamed to work.
def reverse(s):
i = len(s) - 1
sNew = ''
while i >= 0:
sNew = sNew + str(s[i])
i = i -1
return sNew
def reverse(s):
return "".join(s[i] for i in range(len(s)-1, -1, -1))
Blender's answer is lovely, but for a very long string, it will result in a whopping RuntimeError: maximum recursion depth exceeded. One might refactor the same code into a while loop, as one frequently must do with recursion in python. Obviously still bad due to time and memory issues, but at least will not error.
def reverse(text):
answer = ""
while text:
answer = text[0] + answer
text = text[1:]
return answer
Today I was asked this same exercise on pen&paper, so I come up with this function for lists:
def rev(s):
l = len(s)
for i,j in zip(range(l-1, 0, -1), range(l//2)):
s[i], s[j] = s[j], s[i]
return s
which can be used with strings with "".join(rev(list("hello")))
This is a way to do it with a while loop:
def reverse(s):
t = -1
s2 = ''
while abs(t) < len(s) + 1:
s2 = s2 + s[t]
t = t - 1
return s2
I have also just solved the coresponding exercise on codeacademy and wanted to compare my approach to others. I have not found the solution I used so far, so I thought that I sign up here and provide my solution to others. And maybe I get a suggestion or a helpful comment on how to improve the code.
Ok here it goes, I did not use any list to store the string, instead I have just accessed the string index. It took me a bit at first to deal with the len() and index number, but in the end it worked :).
def reverse(x):
reversestring = ""
for n in range(len(str(x))-1,-1, -1):
reversestring += x[n]
return reversestring
I am still wondering if the reversestring = "" could be solved in a more elegant way, or if it is "bad style" even, but i couldn't find an answer so far.
def reverse(text):
a=""
l=len(text)
while(l>=1):
a+=text[l-1]
l-=1
return a
i just concatenated the string a with highest indexes of text (which keeps on decrementing by 1 each loop).
All I did to achieve a reverse string is use the xrange function with the length of the string in a for loop and step back per the following:
myString = "ABC"
for index in xrange(len(myString),-1):
print index
My output is "CBA"
You can simply reverse iterate your string starting from the last character. With python you can use list comprehension to construct the list of characters in reverse order and then join them to get the reversed string in a one-liner:
def reverse(s):
return "".join([s[-i-1] for i in xrange(len(s))])
if you are not allowed to even use negative indexing you should replace s[-i-1] with s[len(s)-i-1]
You've received a lot of alternative answers, but just to add another simple solution -- the first thing that came to mind something like this:
def reverse(text):
reversed_text = ""
for n in range(len(text)):
reversed_text += text[-1 - n]
return reversed_text
It's not as fast as some of the other options people have mentioned(or built in methods), but easy to follow as we're simply using the length of the text string to concatenate one character at a time by slicing from the end toward the front.
def reverseThatString(theString):
reversedString = ""
lenOfString = len(theString)
for i,j in enumerate(theString):
lenOfString -= 1
reversedString += theString[lenOfString]
return reversedString
This is my solution using the for i in range loop:
def reverse(string):
tmp = ""
for i in range(1,len(string)+1):
tmp += string[len(string)-i]
return tmp
It's pretty easy to understand. I start from 1 to avoid index out of bound.
Here's my contribution:
def rev(test):
test = list(test)
i = len(test)-1
result = []
print test
while i >= 0:
result.append(test.pop(i))
i -= 1
return "".join(result)
You can do simply like this
def rev(str):
rev = ""
for i in range(0,len(str)):
rev = rev + str[(len(str)-1)-i]
return rev
Here is one using a list as a stack:
def reverse(s):
rev = [_t for _t in s]
t = ''
while len(rev) != 0:
t+=rev.pop()
return t
Try this simple and elegant code.
my_string= "sentence"
new_str = ""
for i in my_string:
new_str = i + new_str
print(new_str)
you have got enough answer.
Just want to share another way.
you can write a two small function for reverse and compare the function output with the given string
var = ''
def reverse(data):
for i in data:
var = i + var
return var
if not var == data :
print "No palindrome"
else :
print "Palindrome"
Not very clever, but tricky solution
def reverse(t):
for j in range(len(t) // 2):
t = t[:j] + t[- j - 1] + t[j + 1:- j - 1] + t[j] + t[len(t) - j:]
return t
Pointfree:
from functools import partial
from operator import add
flip = lambda f: lambda x, y: f(y, x)
rev = partial(reduce, flip(add))
Test:
>>> rev('hello')
'olleh'

Categories