implement rfind in Python - python

I am attempting to implement the rfind function in Python without using the built-in rfind method. It should work like the following:
Unlike the original method, takes an input string and a character as a parameter and returns the first index from the right where the character is found. Now I am getting stuck on what to do next..
# main function
inputString = input("Enter here: ")
inputChar = input("Which character would you like to find?")
print(Myrfind(inputString, inputChar))
def Myrfind(text,aChar):
reverseString = text[::-1]
for ch in reverseString:
if ch == aChar:
print()
else:
return -1

The simplest approach, IMHO, would be to just iterate over the string backwards and compare each character:
def myrfind(text, aChar):
for i in range(len(text) - 1, -1, -1):
if text[i] == aChar:
return i
return -1

Your function should be like (with minimal changes in current code):
def Myrfind(text,aChar):
reverseString = text[::-1]
for i, c in enumerate(reverseString): # enumerate() to iterate along with index
if c == aChar:
return len(text) - i - 1 # Return len(char) - i -1 since reverse string
else: # Return -1 if function is not
return -1 # exited by for loop
Sample run:
>>> Myrfind('Hello', 'o')
4
>>> Myrfind('Hello', 'l')
3
>>> Myrfind('Hello', 'e')
1
>>> Myrfind('Hello', 'a') # 'a' not in string
-1

So, in ch you have the character, not the index of the character, so even if you find it, you won't be able to know its index (you just know that the character is in your text string, nothing else)
Also, when you find a coincidence, you print... nothing (in print())
And since the return -1 (when not found) is within the for loop, you will stop the execution (returning -1) as soon as a character doesn't match the looked up character (you should be very familiar with the return statement)
You reverse the string, but that is probably not very... "adviseable", because then your indexes get reversed. For instance, let's say you want to find the last l in Hello. You are expecting:
H e l l o
Index 0 1 2 3 4
And that should be 3, but since you reverse it, and start walking it from left to right, you get:
o l l e H
Index 0 1 2 3 4
And the first match is in 1, now... You can still do it, though... You can substract that index to the total lenght, and you should get it.
Firstly, I would recommend you read what the enumerate built-in does (to not only get the character, but also the index)
A pretty close thing to what you have could be:
inputString = input("Enter here: ")
inputChar = input("Which character would you like to find?")
def Myrfind(text,aChar):
reverseString = text[::-1]
for i, ch in enumerate(reverseString):
if ch == aChar:
return len(text) - 1 - i
return -1
print(Myrfind(inputString, inputChar))
Or, instead of inverting the array, just start reading from the right (see what range does)
def Myrfind(text,aChar):
for i in range(len(text) - 1, -1, -1):
ch = text[i]
if ch == aChar:
return i
return -1

Related

Recursive function to obtain non-repeated characters from string

I have this exercise:
Write a recursive function that takes a string and returns all the characters that are not repeated in said string.
The characters in the output don't need to have the same order as in the input string.
First I tried this, but given the condition for the function to stop, it never evaluates the last character:
i=0
lst = []
def list_of_letters_rec(str=""):
if str[i] not in lst and i < len(str) - 1:
lst.append(str[i])
list_of_letters_rec(str[i+1:])
elif str[i] in lst and i < len(str) - 1:
list_of_letters_rec(str[i+1:])
elif i > len(str) - 1:
return lst
return lst
word = input(str("Word?"))
print(list_of_letters_rec(word))
The main issue with this function is that it never evaluates the last character.
An example of an output:
['a', 'r', 'd', 'v'] for input 'aardvark'.
Since the characters don't need to be ordered, I suppose a better approach would be to do the recursion backwards, and I also tried another approach (below), but no luck:
lst = []
def list_of_letters_rec(str=""):
n = len(str) - 1
if str[n] not in lst and n >= 0:
lst.append(str[n])
list_of_letters_rec(str[:n-1])
elif str[n] in lst and n >= 0:
list_of_letters_rec(str[:n-1])
return lst
word = input(str("Word?"))
print(list_of_letters_rec(word))
Apparently, the stop conditions are not well defined, especially in the last one, as the output I get is
IndexError: string index out of range
Could you give me any hints to help me correct the stop condition, either in the 1st or 2nd try?
You can try:
word = input("> ")
result = [l for l in word if word.count(l) < 2]
> aabc
['b', 'c']
Demo
One improvement I would offer on #trincot's answer is the use of a set, which has better look-up time, O(1), compared to lists, O(n).
if the input string, s, is empty, return the empty result
(inductive) s has at least one character. if the first character, s[0] is in the memo, mem, the character has already been seen. Return the result of the sub-problem, s[1:]
(inductive) The first character is not in the memo. Add the first character to the memo and prepend the first character to the result of the sub-problem, s[1:]
def list_of_letters(s, mem = set()):
if not s:
return "" #1
elif s[0] in mem:
return list_of_letters(s[1:], mem) #2
else:
return s[0] + list_of_letters(s[1:], {*mem, s[0]}) #3
print(list_of_letters("aardvark"))
ardvk
Per your comment, the exercise asks only for a string as input. We can easily modify our program to privatize mem -
def list_of_letters(s): # public api
def loop(s, mem): # private api
if not s:
return ""
elif s[0] in mem:
return loop(s[1:], mem)
else:
return s[0] + loop(s[1:], {*mem, s[0]})
return loop(s, set()) # run private func
print(list_of_letters("aardvark")) # mem is invisible to caller
ardvk
Python's native set data type accepts an iterable which solves this problem instantly. However this doesn't teach you anything about recursion :D
print("".join(set("aardvark")))
akdrv
Some issues:
You miss the last character because of i < len(str) - 1 in the conditionals. That should be i < len(str) (but read the next points, as this still needs change)
The test for if i > len(str) - 1 should come first, before doing anything else, otherwise you'll get an invalid index reference. This also makes the other conditions on the length unnecessary.
Don't name your variable str, as that is already a used name for the string type.
Don't populate a list that is global. By doing this, you can only call the function once reliably. Any next time the list will still have the result of the previous call, and you'll be adding to that. Instead use the list that you get from the recursive call. In the base case, return an empty list.
The global i has no use, since you never change its value; it is always 0. So you should just reference index [0] and check that the string is not empty.
Here is your code with those corrections:
def list_of_letters_rec(s=""):
if not s:
return []
result = list_of_letters_rec(s[1:])
if s[0] not in result:
result.append(s[0])
return result
print(list_of_letters_rec("aardvark"))
NB: This is not the most optimal way to do it. But I guess this is what you are asked to do.
A possible solution would be to just use an index instead of splicing the string:
def list_of_letters_rec(string="", index = 0, lst = []):
if(len(string) == index):
return lst
char = string[index]
if string.count(char) == 1:
lst.append(char)
return list_of_letters_rec(string, index+1, lst)
word = input(str("Word?"))
print(list_of_letters_rec(word))

Getting the middle character in a odd length string

def get_middle_character(odd_string):
variable = len(odd_string)
x = str((variable/2))
middle_character = odd_string.find(x)
middle_character2 = odd_string[middle_character]
return middle_character2
def main():
print('Enter a odd length string: ')
odd_string = input()
print('The middle character is', get_middle_character(odd_string))
main()
I need to figure out how to print the middle character in a given odd length string. But when I run this code, I only get the last character. What is the problem?
You need to think more carefully about what your code is actually doing. Let's do this with an example:
def get_middle_character(odd_string):
Let's say that we call get_middle_character('hello'), so odd_string is 'hello':
variable = len(odd_string) # variable = 5
Everything is OK so far.
x = str((variable/2)) # x = '2'
This is the first thing that is obviously odd - why do you want the string '2'? That's the index of the middle character, don't you just want an integer? Also you only need one pair of parentheses there, the other set is redundant.
middle_character = odd_string.find(x) # middle_character = -1
Obviously you can't str.find the substring '2' in odd_string, because it was never there. str.find returns -1 if it cannot find the substring; you should use str.index instead, which gives you a nice clear ValueError when it can't find the substring.
Note that even if you were searching for the middle character, rather than the stringified index of the middle character, you would get into trouble as str.find gives the first index at which the substring appears, which may not be the one you're after (consider 'lolly'.find('l')...).
middle_character2 = odd_string[middle_character] # middle_character2 = 'o'
As Python allows negative indexing from the end of a sequence, -1 is the index of the last character.
return middle_character2 # return 'o'
You could actually have simplified to return odd_string[middle_character], and removed the superfluous assignment; you'd have still had the wrong answer, but from neater code (and without middle_character2, which is a terrible name).
Hopefully you can now see where you went wrong, and it's trivially obvious what you should do to fix it. Next time use e.g. Python Tutor to debug your code before asking a question here.
You need to simply access character based on index of string and string slicing. For example:
>>> s = '1234567'
>>> middle_index = len(s)/2
>>> first_half, middle, second_half = s[:middle_index], s[middle_index], s[middle_index+1:]
>>> first_half, middle, second_half
('123', '4', '567')
Explanation:
str[:n]: returns string from 0th index to n-1th index
str[n]: returns value at nth index
str[n:]: returns value from nth index till end of list
Should be like below:
def get_middle_character(odd_string):
variable = len(odd_string)/2
middle_character = odd_string[variable +1]
return middle_character
i know its too late but i post my solution
I hope it will be useful ;)
def get_middle_char(string):
if len(string) % 2 == 0:
return None
elif len(string) <= 1:
return None
str_len = int(len(string)/2))
return string[strlen]
reversedString = ''
print('What is your name')
str = input()
idx = len(str)
print(idx)
str_to_iterate = str
for char in str_to_iterate[::-1]:
print(char)
evenodd = len(str) % 2
if evenodd == 0:
print('even')
else:
print('odd')
l = str
if len(l) % 2 == 0:
x = len(l) // 2
y = len(l) // 2 - 1
print(l[x], l[y])
else:
n = len(l) // 2
print(l[n])

Remove Single Char in String Python 2.7

I have written the above program. The program supposed to do remove chr from str if str has chr in it and character follow chr is different than chr.
Can anyone here help me what's going on this? Why is not working as supposed? I see some problems with function calling inside a function.
def removesingleton(str,chr):
'''
(str,str)->(str)
Returns str with removed single chr
>>>removesingleton("Welcomee","e")
Wlcomee
>>>removesingleton("XabXXaX","X")
abXXa
'''
output, index = "", 0
if str:
for char in str:
if char == chr:
if index+1 < len(str) and str[index+1] == chr:
output += str[:index+2]
removesingleton(str[index+2:],chr)
else:
removesingleton(str[index+1:],chr)
else:
output += str[index]
removesingleton(str[index+1:],chr)
index += 1
return output
print removesingleton("XabXXaX","X")
You don't need any of the recursive calls. They're completely unnecessary, since you're doing a loop over the whole string within the single call. (You were also ignoring the return value, so there was not much point in recursing in the first place.)
What you do need is to check both the next character and the previous one to see if the current character is part of a repeated sequence. You don't need to do any slicing, nor do you even need an explicit loop. Here's a working version of the code, distilled down to a single generator expression inside a str.join call:
def removesingleton(s, ch):
'''
(str,str)->(str)
Returns a copy of s with all non-repeated instances of ch removed
>>>removesingleton("Welcomee","e")
Wlcomee
>>>removesingleton("XabXXaX","X")
abXXa
'''
return "".join(c for i, c in enumerate(s) # enumerate gives us our index
if c != ch or # keep any of: non-matching characters
(i > 0 and s[i-1] == ch) or # previous character was the same
(i < len(s)-1 and s[i+1] == ch)) # next character is the same

Search for a pattern in a string in python

Question: I am very new to python so please bear with me. This is a homework assignment that I need some help with.
So, for the matchPat function, I need to write a function that will take two arguments, str1 and str2, and return a Boolean indicating whether str1 is in str2. But I have to use an asterisk as a wild card in str1. The * can only be used in str1 and it will represent one or more characters that I need to ignore. Examples of matchPat are as follow:
matchPat ( 'a*t*r', 'anteaters' ) : True
matchPat ( 'a*t*r', 'albatross' ) : True
matchPat ( 'a*t*r', 'artist' ) : False
My current matchPat function can tell whether the characters of str1 are in str2 but I don't really know how I could tell python (by using the * as a wild card) to look for 'a' (the first letter) and after it finds a, skip the next 0 or more characters until it finds the next letter(which would be 't' in the example) and so on.
def matchPat(str1,str2):
## str(*)==str(=>1)
if str1=='':
return True
elif str2=='':
return False
elif str1[0]==str2[0]:
return matchPat(str1[2],str2[len(str1)-1])
else: return True
Python strings have the in operator; you can check if str1 is a substring of str2 using str1 in str2.
You can split a string into a list of substrings based on a token. "a*b*c".split("*") is ["a","b","c"].
You can find the offset of next occurrence of a substring in a string using the string's find method.
So the problem of wildcard matching becomes:
split the pattern into parts which were separated by astrix
for each part of the pattern
can we find this after the previous part's locations?
You are going to have to cope with corner cases like patterns that start with or end with an asterisk or have two asterisk beside each other and so on. Good luck!
There is a find() method of strings that searches for a substring from a particular point, returning either its index (if found) or -1 if not found. The index() method is similar but raises an exception if the target string is not found.
I'd suggest that you first split the pattern string on "*". This will give you a list of chunks to look for. Set the starting position to zero, and for each element in the list of chunks, do a find() or index() from the current position.
If you find the current chunk then work out from its starting position and length where to start searching for the next chunk and update the starting position. If you find all the chunks then the target string matches the pattern. If any chunk is missing then the pattern search should fail.
Since this is homework I am hoping that gives you enough of an idea to move on.
The basic idea here is to compare each character in str1 and str2, and if char in str1 is "*", find that character in str2 which is the character next to the "*" in str1.
Assuming that you are not going to use any function, (except find(), which can be implemented easily), this is the hard way (the code is straight-forward but messy, and I've commented wherever possible)-
def matchPat(str1, str2):
index1 = 0
index2 = 0
while index1 < len(str1):
c = str1[index1]
#Check if the str2 has run it's course.
if index2 >= len(str2):
#This needs to be checked,assuming matchPatch("*", "") to be true
if(len(str2) == 0 and str1 == "*"):
return True
return False
#If c is not "*", then it's normal comparision.
if c != "*":
if c != str2[index2]:
return False
index2 += 1
#If c is "*", then you need to increment str1,
#search for the next value in str2,
#and update index2
else:
index1 += 1
if(index1 == len(str1)):
return True
c = str1[index1]
#Search the character in str2
i = str2.find(c, index2)
#If search fails, return False
if(i == -1):
return False
index2 = i + 1
index1 += 1
return True
OUTPUT -
print matchPat("abcde", "abcd")
#False
print matchPat("a", "")
#False
print matchPat("", "a")
#True
print matchPat("", "")
#True
print matchPat("abc", "abc")
#True
print matchPat("ab*cd", "abacacd")
#False
print matchPat("ab*cd", "abaascd")
#True
print matchPat ('a*t*r', 'anteater')
#True
print matchPat ('a*t*r', 'albatross')
#True
print matchPat ('a*t*r', 'artist')
#False
Without giving you the complete answer, first, split the str1 string into a list of strings on the '*' character. I usually call str1 the "needle" and str2 the "haystack", since you are looking for the needle in the haystack.
needles = needle.split('*')
Next, have a counter (which I will call i) start at 0. You will always be looking at haystack[i:] for the next string in needles.
In pseudocode, it'll look like this:
needles = needle.split('*')
i = 0
loop through all strings in needles:
if current needle not in haystack[i:], return false
increment i to just after the occurence of the current needle in haystack (use the find() string method or write your own function to handle this)
return true
Are you allowed to use regular expressions? If so, the function you're looking for already exists in the re.search function:
import re
bool(re.search('a.t.r', 'anteasters')) # True
bool(re.search('a.t.r', 'artist' )) # False
And if asterisks are a strict necessity, you can use regular expressions for that, too:
newstr = re.sub('\*', '.', 'a*t*r') # Replace * with .
bool(re.search(newstr, 'anteasters')) # Search using the new string
If regular expressions aren't allowed, the simplest way to do that would be to look at substrings of the second string that are the same length as the first string, and compare the two. Something like this:
def matchpat(str1, str2):
if len(str1) > len(str2): return False #Can't match if the first string is longer
for i in range(0, len(str2)-len(str1)+1):
substring = str2[i:i+len(str1)] # create substring of same length as first string
for j in range(0, len(str1)):
matched = False # assume False until match is found
if str1[j] != '*' and str1[j] != substring[j]: # check each character
break
matched = True
if matched == True: break # we don't need to keep searching if we've found a match
return matched

Find index of last occurrence of a substring in a string

I want to find the position (or index) of the last occurrence of a certain substring in given input string str.
For example, suppose the input string is str = 'hello' and the substring is target = 'l', then it should output 3.
How can I do this?
Use .rfind():
>>> s = 'hello'
>>> s.rfind('l')
3
Also don't use str as variable name or you'll shadow the built-in str().
You can use rfind() or rindex()
Python2 links: rfind() rindex()
>>> s = 'Hello StackOverflow Hi everybody'
>>> print( s.rfind('H') )
20
>>> print( s.rindex('H') )
20
>>> print( s.rfind('other') )
-1
>>> print( s.rindex('other') )
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: substring not found
The difference is when the substring is not found, rfind() returns -1 while rindex() raises an exception ValueError (Python2 link: ValueError).
If you do not want to check the rfind() return code -1, you may prefer rindex() that will provide an understandable error message. Else you may search for minutes where the unexpected value -1 is coming from within your code...
Example: Search of last newline character
>>> txt = '''first line
... second line
... third line'''
>>> txt.rfind('\n')
22
>>> txt.rindex('\n')
22
Use the str.rindex method.
>>> 'hello'.rindex('l')
3
>>> 'hello'.index('l')
2
Not trying to resurrect an inactive post, but since this hasn't been posted yet...
(This is how I did it before finding this question)
s = "hello"
target = "l"
last_pos = len(s) - 1 - s[::-1].index(target)
Explanation: When you're searching for the last occurrence, really you're searching for the first occurrence in the reversed string. Knowing this, I did s[::-1] (which returns a reversed string), and then indexed the target from there. Then I did len(s) - 1 - the index found because we want the index in the unreversed (i.e. original) string.
Watch out, though! If target is more than one character, you probably won't find it in the reversed string. To fix this, use last_pos = len(s) - 1 - s[::-1].index(target[::-1]), which searches for a reversed version of target.
Try this:
s = 'hello plombier pantin'
print (s.find('p'))
6
print (s.index('p'))
6
print (s.rindex('p'))
15
print (s.rfind('p'))
For this case both rfind() and rindex() string methods can be used, both will return the highest index in the string where the substring is found like below.
test_string = 'hello'
target = 'l'
print(test_string.rfind(target))
print(test_string.rindex(target))
But one thing should keep in mind while using rindex() method, rindex() method raises a ValueError [substring not found] if the target value is not found within the searched string, on the other hand rfind() will just return -1.
The more_itertools library offers tools for finding indices of all characters or all substrings.
Given
import more_itertools as mit
s = "hello"
pred = lambda x: x == "l"
Code
Characters
Now there is the rlocate tool available:
next(mit.rlocate(s, pred))
# 3
A complementary tool is locate:
list(mit.locate(s, pred))[-1]
# 3
mit.last(mit.locate(s, pred))
# 3
Substrings
There is also a window_size parameter available for locating the leading item of several items:
s = "How much wood would a woodchuck chuck if a woodchuck could chuck wood?"
substring = "chuck"
pred = lambda *args: args == tuple(substring)
next(mit.rlocate(s, pred=pred, window_size=len(substring)))
# 59
Python String rindex() Method
Description
Python string method rindex() returns the last index where the substring str is found, or raises an exception if no such index exists, optionally restricting the search to string[beg:end].
Syntax
Following is the syntax for rindex() method −
str.rindex(str, beg=0 end=len(string))
Parameters
str − This specifies the string to be searched.
beg − This is the starting index, by default its 0
len − This is ending index, by default its equal to the length of the string.
Return Value
This method returns last index if found otherwise raises an exception if str is not found.
Example
The following example shows the usage of rindex() method.
Live Demo
!/usr/bin/python
str1 = "this is string example....wow!!!";
str2 = "is";
print str1.rindex(str2)
print str1.index(str2)
When we run above program, it produces following result −
5
2
Ref: Python String rindex() Method
- Tutorialspoint
If you don't wanna use rfind then this will do the trick/
def find_last(s, t):
last_pos = -1
while True:
pos = s.find(t, last_pos + 1)
if pos == -1:
return last_pos
else:
last_pos = pos
# Last Occurrence of a Character in a String without using inbuilt functions
str = input("Enter a string : ")
char = input("Enter a character to serach in string : ")
flag = 0
count = 0
for i in range(len(str)):
if str[i] == char:
flag = i
if flag == 0:
print("Entered character ",char," is not present in string")
else:
print("Character ",char," last occurred at index : ",flag)
you can use rindex() function to get the last occurrence of a character in string
s="hellloooloo"
b='l'
print(s.rindex(b))
str = "Hello, World"
target='l'
print(str.rfind(target) +1)
or
str = "Hello, World"
flag =0
target='l'
for i,j in enumerate(str[::-1]):
if target == j:
flag = 1
break;
if flag == 1:
print(len(str)-i)

Categories