I think you're expecting rfind to return the index of the rightmost character in the first/leftmost match for "what". It actually returns the index of the leftmost character in the last/rightmost match for "what". To quote the documentation:
str.rfind(sub[, start[, end]])Return the highest index in the string where substring sub is found, such that sub is contained within
s[start:end]. Optional arguments start and end are interpreted as in slice notation. Return-1on failure.
"ab c ab".find("ab") would be 0, because the leftmost occurrence is on the left end.
"ab c ab".rfind("ab") would be 5, because the rightmost occurrence is starts at that index.
if in vs. str.rfind()
Why do rfind and find return the same values in Python 2.6.5? - Stack Overflow
string - implement rfind in Python - Stack Overflow
How to find the last occurrence of an item in a Python list - Stack Overflow
a coworker asked me Python advice. I'm a n00b...This is what I offered.
substring=("foo","bar")
string=("1","2","3",("foo","bar"))
if substring in string:
print TrueHe did this (something like this, pulling from memory):
string.rfind(substring) != -1
print TrueCan someone shed light on both?
Reading the documentation for rfind() it seems like it's returning the index of the substring so the != -1 would simply say 'does not exist'?
I only wonder if this is the right context to use rfind().
FWIW, this is on Python 2.4.3 if it matters.
Thanks! Much appreciated!
I think you're expecting rfind to return the index of the rightmost character in the first/leftmost match for "what". It actually returns the index of the leftmost character in the last/rightmost match for "what". To quote the documentation:
str.rfind(sub[, start[, end]])Return the highest index in the string where substring sub is found, such that sub is contained within
s[start:end]. Optional arguments start and end are interpreted as in slice notation. Return-1on failure.
"ab c ab".find("ab") would be 0, because the leftmost occurrence is on the left end.
"ab c ab".rfind("ab") would be 5, because the rightmost occurrence is starts at that index.
find() will return the index of the first match. But rfind will give you the last occurence of the pattern. It will be clear if you try to match repeated match case.
check this Example >>> string='hey! how are you harish'
>>>string.find('h')
>>>0 #it matched for first 'h' in the string
>>> string.rfind('h')
22 #it matched for the last 'h' in the string
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
If you are actually using just single letters like shown in your example, then str.rindex would work handily. This raises a ValueError if there is no such item, the same error class as list.index would raise. Demo:
>>> li = ["a", "b", "a", "c", "x", "d", "a", "6"]
>>> ''.join(li).rindex('a')
6
For the more general case you could use list.index on the reversed list:
>>> len(li) - 1 - li[::-1].index('a')
6
The slicing here creates a copy of the entire list. That's fine for short lists, but for the case where li is very long, it may be more efficient to use a reverse iteration and avoid the copy:
def list_rindex(li, x):
for i in reversed(range(len(li))):
if li[i] == x:
return i
raise ValueError("{} is not in list".format(x))
One-liner version:
next(i for i in reversed(range(len(li))) if li[i] == 'a')
A one-liner that's like Ignacio's except a little simpler/clearer would be
max(loc for loc, val in enumerate(li) if val == 'a')
It seems very clear and Pythonic to me: you're looking for the highest index that contains a matching value. No nexts, lambdas, reverseds or itertools required.
If you are using ipython (I can warmly recommend) you can type ?? before a command in order to see its docstring.
Doing so for string.rfind:
Docstring:
S.rfind(sub[, start[, end]]) -> int
Return the highest index in S where substring sub is found, such that sub is contained within S[start:end]. Optional arguments start and end are interpreted as in slice notation.
Return -1 on failure.
Type: builtin_function_or_method
and for string.find:
Docstring:
S.find(sub[, start[, end]]) -> int
Return the lowest index in S where substring sub is found, such that sub is contained within S[start:end]. Optional arguments start and end are interpreted as in slice notation.
Return -1 on failure.
Type: builtin_function_or_method
I took the liberty to highlight the important parts.
What it means is that both will return the same index if there is only one substring (i.e. 'k' in your case) found.
If you are still unsure about how str.rfind and str.find differ from each other, try the same thing with:
string = 'kooook'
Hope that helps and happy coding!
As far as I know, rfind() do the same as find(), but return the last index.
Being only one 'k', the two of the return the same. With 'o', the result will be different.