recursive function to find that string 1 substring of string2 - python

i try to find a recursive function that take two string and returns true if string1 is a substring of string2 and false otherwise by check recursively if str2 starts with str1.
i try this code but it does not work i do not know why !
def main():
s1 = input("enter string")
s2 = input("enter steing")
sub = subs(s1,s2)
print(sub)
def subs(s1, s2):
if s2 == 0:
return True
else:
if s2.startswith((s1)):
subs(s1, s2[1:])
return True
main()
thank you !

Your program has a few syntactic issues first:
You're invoking the subs function before you're actually defining it.
Your indent of main() is off.
subs is an inner function of main. While not technically incorrect, using inner functions can make your code more difficult to read.
You also have some semantic issues:
subs is only returning true on the escape condition, there is no default return value. This is poor practice
subs is checking if s2 == 0, which it will never be - strings won't equal 0. Empty strings are Falsy, so you can check if the string is empty by using if not s2: instead
Your logic dictates that the recursion will ONLY occur if s2 starts with s1, meaning if s1='ab' and s2='habc', it will not trigger recursion, even though s1 is a substring of s2.
My suggestion would be to reexamine your algorithm. Begin with identifying how you will begin looking for a candidate substring first, then what your escape conditions are, then how you break the problem into a smaller problem.

I rewrote the code you had written, but kept the intuition same. Major problems were:
1.Indentation mistakes at many places.
2.function definition after calling it.
3.Wrong method to find empty string.
def main():
def subs(s1, s2,k):
#If input string is empty .
if k==0 and not s2.strip():
print("Yes")
return 0
#String 1 not empty and search for the sub-string.
elif s1.strip() and s1.startswith(s2):
print("Yes")
return 0
#String 1 not empty and sub-string not matched.
elif s1.strip():
subs(s1[1:],s2,1)
#String empty and sub-string not match.
else :
print("No")
s1 = input("enter string")
s2 = input("enter sub-string")
sub = subs(s1,s2,0)
#print(sub)
main()

Related

how does the lower recursion works in the code?

def isPal(s):
if len(s) <= 1:
print(s)
else:
print(s)
s[0] == s[-1] and isPal((s[1:-1]))
print(s)
print("HI")
x = isPal("deleveled")
print(x)
Output:
deleveled
elevele
level
eve
v
HI
eve
HI
level
HI
elevele
HI
deleveled
HI
None
Let's break down the program.
Firstly, if the string given to isPal() is one or zero characters, it's printed. In other words, once we can't simplify any more, we stop simplifying and just output what we have.
Otherwise (when we have two or more characters), we check that the first and last character are equal, and then perform the same algorithm on the string without these two characters. This continues until we have one or zero characters, as described above.
The reason the word is rebuilding at the end is that you have printed the string again after your recursive function call. So after going 'deeper' into your word, you print where you came from too.
EDIT: The reason 'HI' is printed is that after you've done your going 'deeper' into the word and have come back out, you print 'HI' each time. So every time you take one step back out of the program (one more letter back at the start and end), you print 'HI'.
I think the issue with your code is that you've not actually told the function to answer the 'isPal' question with a True or False.
def isPal(s):
if len(s) <= 1:
print(s)
return True
else:
print(s)
return (s[0] == s[-1] and isPal((s[1:-1])))
x = isPal("deleveled")
print(x)
This code will now return True or False depending on whether your algorithm detects that the string is a palindrome or not.
Your code actually did what you wanted it to, you just hadn't returned the result of your check.

Using Recursion to Determine if a Word is a Palindrome

I am trying to determine if a given word is a palindrome.
The goal of my code is that the function will take a word, and remove it of any punctuation or spaces. If the length of the word is 0 or 1, it is returned that the word is a palindrome. I then check if the first and last letter are the same. If they aren't, it is returned that it is not a palindrome. If they first and last letters the same, I then want to replace those two letters with spaces and call my function again. The reason I replace the letters with spaces is so that it will be edited by my initial edit statements.
def palindrome(word):
editWord = word.strip(" ").strip("!").strip("?")
stringOne = "A palindrome"
stringTwo = "Not a palindrome"
if len(editWord) == 0 or len(editWord) == 1:
return stringOne
elif editWord[0] != editWord[-1]:
return stringTwo
else:
word = editWord.replace(editWord[0], " ").replace(editWord[-1], " ")
palindrome(word)
return stringOne
print(palindrome("area"))
When tested with single letters it functions properly, as well if I test words like 'are' which obviously is not a palindrome. However, if I call the word area it returns "A palindrome" when it is not. This makes it seem like it is not calling my function again. Any suggestions on why this is happening?
For recursion to work properly here, your else statement should say something along the lines of "the word is a palindrome if the outer characters are equal and the remainder is also a palindrome". Instead, your code is replacing all occurrences of the outer characters with spaces, checking if the word is a palindrome, and ignoring the result to always return "yes".
You can do a proper recursion using slicing instead of replacement:
else:
return palindrome(editWord[1:-1])
Another alternative to replacing the letters while still doing this recursively to to keep track of the index in the word and increment it on recursion. This saves you from having to make new slices on each recursion. In this case your edge case will be when the index is in the middle of the word.
def palindrome(word, i = 0):
if i >= len(word)//2:
return True
if word[i] != word[-(i+1)]:
return False
return palindrome(word, i+1)
palindrome("mrowlatemymetalworm") # true

Check python function determine isogram from codewars

An isogram is a word that has no repeating letters, consecutive or non-consecutive. Implement a function that determines whether a string that contains only letters is an isogram. Assume the empty string is an isogram. Ignore letter case.
is_isogram("Dermatoglyphics" ) == true
is_isogram("aba" ) == false
is_isogram("moOse" ) == false # -- ignore letter case
Here is my code:
def is_isogram(string):
string = string.lower()
for char in string:
if string.count(char) > 1:
return False
else:
return True
And when I tried to run the test code Test.assert_equals(is_isogram("moOse"), False, "same chars may not be same case" ) It failed, but I thought I did convert everything into lowercase. Can someone help?
Try this:
def is_isogram(string):
string = string.lower()
for char in string:
if string.count(char) > 1:
return False
return True
In your code when is_isogram("moose") is called, it will see that the first character's ('m') count is not greater than 1. So it will return True. Once it hits the return statement, it will stop the execution for the rest string. So you should really write return True only after for-loop to make sure that the function checks for the whole string.
If however, at any point, it finds a character's count to be greater than 1, then it will simply return False and stop executing because there's no point of checking any more when one point is found where condition does not hold.
How about using sets? Casting the string into a set will drop the duplicate characters, causing isograms to return as True, as the length of the set won't differ from the length of the original string:
def is_isogram(s):
s = s.lower()
return len(set(s)) == len(s)
print is_isogram("Dermatoglyphics")
print is_isogram("aba")
print is_isogram("moOse")
print is_isogram("")
This outputs:
True
False
False
True
Try this :
def is_isogram(s):
string = s.lower()
if len(s) == len(set(string)):
return True
return False
Try this out:
def is_isogram(string):
return len(string) == len(set(string.lower()))
"Implement a function that determines whether a string that contains only letters is an isogram."
By using sets, you can create unique elements. So if there are any repeating numbers, it will only select one. By calling len() on these strings, you can compare the length to the original.
Sorry if I explained it poorly. I am working on this.
let us define an isogram well:
according to wikipedia An Isogram is a word in which no letter occurs more than once.
check here for more about an isogram
just remind letter
I write this code and it works for me :
def is_isogram(argument):
print(len(argument))
if isinstance(argument,str):
valeur=argument.lower()
if not argument:
return False
else:
for char in valeur:
if valeur.count(char)>1 or not char.isalpha():
return False
return True
else:
raise TypeError("need a string ")
NB: the hidden test is the fact that you must check if the char in the string is a alpha character a-z, when i add this it pass all the hiddens tests
up vote if this help
I reckon this might not be the best solution in terms of maximizing memory space and time. This answer is just for intuition purposes using a dictionary and two for loops:
def is_isogram(string):
#your code here
#create an empty dictionary
m={}
#loop through the string and check for repeating characters
for char in string:
#make all characters lower case to ignore case variations
char = char.lower()
if char in m:
m[char] += 1
else:
m[char] = 1
#loop through dictionary and get value counts.
for j, v in m.items():
#if there is a letter/character with a count > 1 return False
if v > 1:
return False
#Notice the scope of the "return True" command. It is outside.
return True

Small issue with Palindrome program

I've been working on this Palindrome program and am really close to completing it.Close to the point that it's driving me a bit crazy haha.
The program is supposed to check each 'phrase' to determine if it is a Palindrome or not and return a lowercase version with white space and punctuation removed if it is in fact a Palindrome. Otherwise, if not, it's supposed to return None.
I'm just having an issue with bringing my test data into the function. I can't seem to think of the correct way of dealing with it. It's probably pretty simple...Any ideas?
Thanks!
import string
def reverse(word):
newword = ''
letterflag = -1
for numoletter in word:
newword += word[letterflag]
letterflag -= 1
return newword
def Palindromize(phrase):
for punct in string.punctuation:
phrase= phrase.replace(punct,'')
phrase = str(phrase.lower())
firstindex = 0
secondindex = len(phrase) - 1
flag = 0
while firstindex != secondindex and firstindex < secondindex:
char1 = phrase[firstindex]
char2 = phrase[secondindex]
if char1 == char2:
flag += 1
else:
break
firstindex += 1
secondindex -= 1
if flag == len(phrase) // (2):
print phrase.strip()
else:
print None
def Main():
data = ['Murder for a jar of red rum',12321, 'nope', 'abcbA', 3443, 'what',
'Never odd or even', 'Rats live on no evil star']
for word in data:
word == word.split()
Palindromize(word)
if __name__ == '__main__':
Main()
Maybe this line is causing the problems.
for word in data:
word == word.split() # This line.
Palindromize(word)
You're testing for equality here, rather than reassigning the variable word which can be done using word = word.split(). word then becomes a list, and you might want to iterate over the list using
for elem in word:
Palindromize(elem)
Also, you seem to be calling the split method on int, which is not possible, try converting them to strings.
Also, why do you convert the phrase to lower case in the for loop, just doing it once will suffice.
At the "core" of your program, you could do much better in Python, using filter for example. Here is a quick demonstration:
>>> phrase = 'Murder for a jar of red rum!'
>>> normalized = filter(str.isalnum, phrase.lower())
>>> normalized
'murderforajarofredrum'
>>> reversed = normalized[-1::-1]
>>> reversed
'murderforajarofredrum'
# Test is it is a palindrome
>>> reversed == normalized
True
Before you go bananas, let's rethink the problem:
You have already pointed out that Palindromes only make sense in strings without punctuation, whitespace, or mixed case. Thus, you need to convert your input string, either by removing the unwanted characters or by picking the allowed ones. For the latter, one can imagine:
import string
clean_data = [ch for ch in original_data if ch in string.ascii_letters]
clean_data = ''.join(clean_data).lower()
Having the cleaned version of the input, one might consider the third parameter in slicing of strings, particularly when it's -1 ;)
Does a comparison like
if clean_data[::-1] == clean_data:
....
ring a bell?
One of the primary errors that i spotted is here:
for word in data:
word==word.split()
Here, there are two mistakes:
1. Double equals make no point here.
2. If you wish to split the contents of each iteration of data, then doing like this doesn't change the original list, since you are modifying the duplicate set called word. To achieve your list, do:
for i in range(data):
data[i]=data[i].split()
This may clear your errors

Got a None return input after different inputs

Hello guys with the code below, after inputting a number and then a char, it returns None. I've got no clue about this one. Any help is welcome.
I've tried printing the values but it changes just on returning!
import string
def get_input_char(char):
char = str.lower(input("Input a letter: "))
if not char in string.ascii_letters or char == "" or char == None:
print("Character " + char + " not valid. Try again.\n")
char = str(get_input_char(char))
else:
return char
print (char)
word_frag = ""
while True:
word_frag += get_input_char("")
print("\nThe current word fragment is " + word_frag)
If your function falls through to the end, after the print statement, it doesn't return anything. The default value returned from a function is None.
As Mark pointed out, the problem is that no value is returned if the first entered value is not valid. There are also a few other things not quite right in your code:
You're using recursion to test for valid values when a loop would be better. This is mainly because of the large overheads involved in calling a function compared to a loop. If you use a loop, you don't need to give the function an argument.
It is better practice to check char is None instead of char == None. Checking for equality may give unexpected results if the object you're testing has been customised to compare equal to None. Checking identity (using is) is much more robust.
However, it is not necessary to check for None at all, since char will always be a string.
Your code implies that only one character is expected, but actually any string contained in ascii_letters would be accepted, e.g. "efgh".
I'd suggest rewriting the function something like this:
def get_input_char():
while True:
char = str.lower(input("Input a letter: "))
if len(char) == 1 and char in string.ascii_letters:
break
else:
print("Character '%s' not valid. Try again.\n" % char)
return char

Categories