I need to make a function in Python 2.7 that does not use any built-in functions to find the last occurrence of a character in a string. It should work like:
string="This is a string with plenty of eeeeees"
string.rfind("e")
But the .rfind has to be replaced with a function created in the code like:
def lastocc(string, char):
# Function code
The below code will iterate over your string, and if it finds the matching character updates the found_at variable with the index of it in the string. It also uses the common idiom of returning -1 if the character is not present in the string.
def last_occurence(s, char):
found_at = -1
index = 0
for s_char in s:
if s_char == char:
found_at = index
index += 1
return found_at
If you could use the len() built-in, you could start your iteration from the end of the string, and take the length-negative_index to find it instead.
I hope that there is not too much built-in functions:
def lastocc(string, char):
m=-1;
i=0;
while i>=0:
try:
if string[i]==char:
m=i;
i+=1
except Exception:
i=-1;
return(m);
print(lastocc("1234561234", "0"))
def lastocc(somestr, char):
return max(i for i,c in enumerate(somestr) if c==char)
Or if you don't want to use any builtins whatsoever, you could do this:
def lastocc(somestr, char):
if not somestr: return -1
if somestr[-1] == char: return len(somestr)-1
return lastocc(somestr[:-1], char)
Related
I'm trying to write a function to return the longest common prefix from a series of strings. Using a debugger, saw that my function reaches the longest common prefix correctly, but then when it reaches the statement to return, it begins reverting to earlier stages of the algorithm.
For test case strs = ["flower","flow","flight"]
The output variable holds the following values:-
f > fl > f
instead of returning fl.
Any help would be appreciated, because I don't really know how to Google for this one. Thank you.
class Solution(object):
def longestCommonPrefix(self, strs, output = ''):
#return true if all chars in string are the same
def same(s):
return s == len(s) * s[0]
#return new list of strings with first char removed from each string
def slicer(list_, list_2 = []):
for string in list_:
string1 = string[1:]
list_2.append(string1)
return list_2
#return string containing first char from each string
def puller(list_):
s = ''
for string in list_:
s += string[0]
return s
#pull first character from each string
s = puller(strs)
#if they are the same
#add one char to output
#run again on sliced list
if same(s):
output += s[0]
self.longestCommonPrefix(slicer(strs), output)
return output
This can be handled with os.path.commonprefix.
>>> import os
>>> strs = ["flower","flow","flight"]
>>> os.path.commonprefix(strs)
'fl'
It doesn't "revert". longestCommonPrefix potentially calls itself - what you're seeing is simply the call-stack unwinding, and flow of execution is returning to the calling code (the line that invoked the call to longestCommonPrefix from which you are returning).
That being said, there's really no need to implement a recursive solution in the first place. I would suggest something like:
def get_common_prefix(strings):
def get_next_prefix_char():
for chars in zip(*strings):
if len(set(chars)) != 1:
break
yield chars[0]
return "".join(get_next_prefix_char())
print(get_common_prefix(["hello", "hey"]))
You are looking at the behavior...the final result...of recursive calls to your method. However, the recursive calls don't do anything to affect the result of the initial execution of the method. If we look at the few lines that matter at the end of your method:
if same(s):
output += s[0]
self.longestCommonPrefix(slicer(strs), output)
return output
The problem here is that since output is immutable, its value won't be changed by calling longestCommonPrefix recursively. So from the standpoint of the outermost call to longestCommonPrefix, the result it will return is determined only by if same(s) is true or false. If it is true it will return s[0], otherwise it will return ''.
The easiest way to fix this behavior and have your recursive call affect the result of the prior call to the method would be to have its return value become the value of output, like this:
if same(s):
output += s[0]
output = self.longestCommonPrefix(slicer(strs), output)
return output
This is a common code pattern when using recursion. Just this change does seem to give you the result you expect! I haven't analyzed your whole algorithm, so I don't know if it becomes "correct" with just this change.
Can you try this? I
class Solution(object):
def longestCommonPrefix(self, strs, output = ''):
#return true if all chars in string are the same
def same(s):
return s == len(s) * s[0]
#return new list of strings with first char removed from each string
def slicer(list_, list_2 = []):
for string in list_:
string1 = string[1:]
list_2.append(string1)
return list_2
#return string containing first char from each string
def puller(list_):
s = ''
for string in list_:
s += string[0]
return s
#pull first character from each string
s = puller(strs)
# Can you Try this revision?
# I think the problem is that your new version of output is being lost when the fourth called function returns to the third and the third returns to the second, etc...
# You need to calculate a new output value before you call recursively, that is true, but you also need a way to 'store' that output when that recursively called function 'returns'. Right now it disappears, I believe.
if same(s):
output += s[0]
output = self.longestCommonPrefix(slicer(strs), output)
return output
Ok, so this is my code, i don't want to use the built in swapcase() method. It does not work for the given string.
def myFunc(a):
for chars in range(0,len(a)):
if a[chars].islower():
a = a.replace(a[chars], a[chars].upper())
elif a[chars].isupper():
a = a.replace(a[chars], a[chars].lower())
return a
print(myFunc("AaAAaaaAAaAa"))
replace changes all the letters and you assign the values back to aso you end up with all upper cases.
def myFunc(a):
# use a list to collect changed letters
new_text = []
for char in a:
if char.islower():
new_text.append(char.upper())
else:
new_text.append(char.lower())
# join the letters back into a string
return ''.join(new_text)
print(myFunc("AaAAaaaAAaAa")) # aAaaAAAaaAaA
or shorter:
def my2ndFunc(text):
return ''.join( a.upper() if a.islower() else a.lower() for a in text)
using a list comprehension and a ternary expression to modify the letter (see Does Python have a ternary conditional operator?)
The problem was that you were doing a replace of all ocurrances of that character in the string. Here you have a working solution:
def myFunc(a):
result = ''
for chars in range(0,len(a)):
print(a[chars])
if a[chars].islower():
result += a[chars].upper()
elif a[chars].isupper():
result += a[chars].lower()
return result
print(myFunc("AaAAaaaAAaAa"))
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
I'm trying to figure out how to write a recursive function (with only one parameter) that returns the number of times the substring “ou” appears in the string. Where I'm confused at is that I'm not allowed to use any built-in string functions other than len, or the string operators [] and [:] for indexing and splicing. So I can't use the find built-in find function
I remember seeing something like this, but it uses two parameters and it also uses the find() method
def count_it(target, key):
index = target.find(key)
if index >= 0:
return 1 + count_it(target[index+len(key):], key)
else:
return 0
Very inefficient, but should work:
def count_it(target):
if len(target) < 2:
return 0
else:
return (target[:2] == 'ou') + count_it(target[1:])
See it working online: ideone
It's basically the same idea as the code you posted, except that it moves only one character at a time through the string instead of using find to jump ahead to the next match.
Try this, it works for the general case (any value of key, not only 'ou'):
def count_it(target, key):
if len(target) < len(key):
return 0
found = True
for i in xrange(len(key)):
if target[i] != key[i]:
found = False
break
if found:
return 1 + count_it(target[len(key):], key)
else:
return count_it(target[1:], key)
I am trying to replace the Nth appearance of a needle in a haystack. I want to do this simply via re.sub(), but cannot seem to come up with an appropriate regex to solve this. I am trying to adapt: http://docstore.mik.ua/orelly/perl/cookbook/ch06_06.htm but am failing at spanning multilines, I suppose.
My current method is an iterative approach that finds the position of each occurrence from the beginning after each mutation. This is pretty inefficient and I would like to get some input. Thanks!
I think you mean re.sub. You could pass a function and keep track of how often it was called so far:
def replaceNthWith(n, replacement):
def replace(match, c=[0]):
c[0] += 1
return replacement if c[0] == n else match.group(0)
return replace
Usage:
re.sub(pattern, replaceNthWith(n, replacement), str)
But this approach feels a bit hacky, maybe there are more elegant ways.
DEMO
Something like this regex should help you. Though I'm not sure how efficient it is:
#N=3
re.sub(
r'^((?:.*?mytexttoreplace){2}.*?)mytexttoreplace',
'\1yourreplacementtext.',
'mystring',
flags=re.DOTALL
)
The DOTALL flag is important.
I've been struggling for a while with this, but I found a solution that I think is pretty pythonic:
>>> def nth_matcher(n, replacement):
... def alternate(n):
... i=0
... while True:
... i += 1
... yield i%n == 0
... gen = alternate(n)
... def match(m):
... replace = gen.next()
... if replace:
... return replacement
... else:
... return m.group(0)
... return match
...
...
>>> re.sub("([0-9])", nth_matcher(3, "X"), "1234567890")
'12X45X78X0'
EDIT: the matcher consists of two parts:
the alternate(n) function. This returns a generator that returns an infinite sequence True/False, where every nth value is True. Think of it like list(alternate(3)) == [False, False, True, False, False, True, False, ...].
The match(m) function. This is the function that gets passed to re.sub: it gets the next value in alternate(n) (gen.next()) and if it's True it replaces the matched value; otherwise, it keeps it unchanged (replaces it with itself).
I hope this is clear enough. If my explanation is hazy, please say so and I'll improve it.
Could you do it using re.findall with MatchObject.start() and MatchObject.end()?
find all occurences of pattern in string with .findall, get indices of Nth occurrence with .start/.end, make new string with replacement value using the indices?
If the pattern ("needle") or replacement is a complex regular expression, you can't assume anything. The function "nth_occurrence_sub" is what I came up with as a more general solution:
def nth_match_end(pattern, string, n, flags):
for i, match_object in enumerate(re.finditer(pattern, string, flags)):
if i + 1 == n:
return match_object.end()
def nth_occurrence_sub(pattern, repl, string, n=0, flags=0):
max_n = len(re.findall(pattern, string, flags))
if abs(n) > max_n or n == 0:
return string
if n < 0:
n = max_n + n + 1
sub_n_times = re.sub(pattern, repl, string, n, flags)
if n == 1:
return sub_n_times
nm1_end = nth_match_end(pattern, string, n - 1, flags)
sub_nm1_times = re.sub(pattern, repl, string, n - 1, flags)
sub_nm1_change = sub_nm1_times[:-1 * len(string[nm1_end:])]
components = [
string[:nm1_end],
sub_n_times[len(sub_nm1_change):]
]
return ''.join(components)
I have a similar function I wrote to do this. I was trying to replicate SQL REGEXP_REPLACE() functionality. I ended up with:
def sql_regexp_replace( txt, pattern, replacement='', position=1, occurrence=0, regexp_modifier='c'):
class ReplWrapper(object):
def __init__(self, replacement, occurrence):
self.count = 0
self.replacement = replacement
self.occurrence = occurrence
def repl(self, match):
self.count += 1
if self.occurrence == 0 or self.occurrence == self.count:
return match.expand(self.replacement)
else:
try:
return match.group(0)
except IndexError:
return match.group(0)
occurrence = 0 if occurrence < 0 else occurrence
flags = regexp_flags(regexp_modifier)
rx = re.compile(pattern, flags)
replw = ReplWrapper(replacement, occurrence)
return txt[0:position-1] + rx.sub(replw.repl, txt[position-1:])
One important note that I haven't seen mentioned is that you need to return match.expand() otherwise it won't expand the \1 templates properly and will treat them as literals.
If you want this to work you'll need to handle the flags differently (or take it from my github, it's simple to implement and you can dummy it for a test by setting it to 0 and ignoring my call to regexp_flags()).