I'm doing an exercise in which I have to remove all occurrences of a string from another string and, although it works, it seems that the program is iterating and infinite amount of times and I can't fix it. I know there is a string.replace() function but I wanted to try to solve the problem without using the fuction.
This is the code:
'''
def remove_all(substr,theStr):
index = theStr.find(substr)
if index > 0:
newstr = ""
while index > 0:
sizsub = len(substr)
newstr = theStr[:index] + theStr[(index + len(substr)):]
index = newstr.find(substr)
return newstr
else:
return theStr
remove_all("an", "banana")
'''
the error message: "TimeLimitError: Program exceeded run time limit. on line 9"
Thanks in advance.
First, you should check if index is greater than -1, not 0, because 0 is the first index.
Inside while you are cuting the initial theStr every time ,which causes newstr to be same thing and stuck in loop.
You can solve this by giving initail value equal to theStr for newstr and cut the newstr instead of theStr inside loop.
def x(substr, theStr):
index = theStr.find(substr)
if index > -1:
newstr = theStr
while index> -1:
sizsub = len(substr)
newstr = newstr[:index] + newstr[index + sizsub:]
index = newstr.find(substr)
return newstr
else:
return theStr
print(x('an', 'banana'))
# prints => ba
Related
I am simply trying to compare one character in a string to its neighbor, but I keep getting a string index out of range error. I can't figure this out.
s = 'azcbobobegghakl'
current = ""
previous = ""
for letter in range(0,len(s)):
if s[letter] <= s[letter+1]:
current += s[letter]
print(current)
Thanks
The if statement was unnecessary. On the last iteration of the loop, s[letter+1] was throwing an error because that index of the string didn't exist. At that point, letter was equal to the length of your string, s. letter+1 was one higher than the length, so the index didn't exist.
There is no need to compare the value of letter to the length of s in the if statement because the loop would end before letter is greater than the length of s.
Solution:
s = 'azcbobobegghakl'
current = ""
previous = ""
for letter in range(0,len(s)):
current += s[letter]
print(current)
while #sedavidw is completely right pointing out the indexing issue, it is not a very pythonic way of doing such a comparison. I'd do something like:
current = ''.join(letter for letter, next_letter in zip(s, s[1:])
if letter <= next_letter)
I think you want to print a letter only if the previous one is less than the current one. The index out of bounds occur because the last index points to (l) but index + 1 points to nothing.
Here is my solution:
s = 'azcbobobegghakl'
current = ""
previous = ""
for letter in range(0,len(s)):
if letter + 1 < len(s): # this is important to prevent the index out of bounds error
if s[letter] <= s[letter+1]:
current += s[letter]
print(current)
Output: abbbeggak
For example: string = aaaacccc, then I need the output to be 4a4c. Is there a way to do this without using any advanced methods, such as libraries or functions?
Also, if someone knows how to do the reverse: turning "4a4c: into aaaacccc, that would be great to know.
This will do the work in one iteration
Keep two temp variable one for current character, another for count of that character and one variable for the result.
Just iterate through the string and keep increasing the count if it matches with the previous one.
If it doesn't then update the result with count and value of character and update the character and count.
At last add the last character and the count to the result. Done!
input_str = "aaaacccc"
if input_str.isalpha():
current_str = input_str[0]
count = 0
final_string = ""
for i in input_str:
if i==current_str:
count+=1
else:
final_string+=str(count)+current_str
current_str = i
count = 1
final_string+=str(count)+current_str
print (final_string)
Another solution and I included even a patchwork reverse operation like you mentioned in your post. Both run in O(n) and are fairly simple to understand. The encode is basically identical one posted by Akanasha, he was just a bit faster in posting his answer while i was writing the decode().
def encode(x):
if not x.isalpha():
raise ValueError()
output = ""
current_l = x[0]
counter = 0
for pos in x:
if current_l != pos:
output += str(counter) + current_l
counter = 1
current_l = pos
else:
counter += 1
return output + str(counter) + current_l
def decode(x):
output = ""
i = 0
while i < len(x):
if x[i].isnumeric():
n = i + 1
while x[n].isnumeric():
n += 1
output += int(x[i:n])*x[n]
i = n
i += 1
return output
test = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasasggggggbbbbdd"
test1 = encode(test)
print(test1)
test2 = decode(test1)
print(test2)
print(test == test2)
yes, you do not need any libraries:
list1 = list("aaaacccc")
letters = []
for i in list1:
if i not in letters:
letters.append(i)
string = ""
for i in letters:
string += str(list1.count(i))
string+=str(i)
print(string)
Basically, it loops through the list, finds the unique letters and then prints the count with the letter itself. Reversing would be the same function, just print the amount.
: Write a function, named foldStrings(string1, string2) that takes, as arguments, two strings. If
the two strings are equal in length, the function returns a string that is formed by alternating characters in each of the two strings. If the two strings are not equal in length, the function returns the string “The two strings are not
equal in length.”
For example, >>>foldStrings(“abc”, “def”)
should return the string “adbecf” and >>>foldStrings(“a”, “bc”)
should return the string “The two strings are not equal in length.”
This is what I have so far:
def foldStrings(str1, str2):
newStr = ""
counter = 0
if len(str2) == len(str1):
while counter < len(str2):
for element in str1:
for index in str2:
newStr = newStr + element
newStr = newStr + index
counter += 1
return newStr
else:
return "The two Strings are not equal in length"
and it prints this: 's1s2s3s4s5s6a1a2a3a4a5a6n1n2n3n4n5n6t1t2t3t4t5t6o1o2o3o4o5o6s1s2s3s4s5s6'
instead of this:
's1a2n3t4o5s6'
You have unnecessarily complicated the problem with three nested loops, when a single loop is required.
Replace:
while counter < len(str2):
for element in str1:
for index in str2:
newStr = newStr + element
newStr = newStr + index
counter += 1
return newStr
With:
for index in range(len(str1)) :
newStr = newStr + str1[index] + str2[index]
return newStr
In the original code, if the string length was for example 6, your code says:
Repeat 6 times:
for every character in str1
for every character in str1
do stuff
so that do stuff is executed 6 x 6 x 6 times! You only want to execute it 6 times suggesting a single loop.
What you were doing wrong was not a python specific issue, but rather an issue with your algorithmic and logical thinking. Mathematically the problem suggests a single iteration, while you had three - nested. In this case you might have manually walked through the code or used a debugger to step through it to demonstrate flaw in thinking here.
You can skip using a counter variable by using range
def foldStrings(str1, str2):
if len(str1) != len(str2):
return "The two Strings are not equal in length"
# This should really be a raise ValueError("The two Strings are not equal in length")
newStr = ''
for i in range(len(str1)):
newStr += str1[i] + str2[i]
return newStr
Here's a slightly more compact way to replace the for loop
newStr = ''.join([x for pair in zip(str1, str2) for x in pair])
#Simple way to do it
def foldStrings(str1, str2):
newStr = ""
counter = 0
if len(str2) == len(str1):
while counter < len(str2):
newStr = newStr + str1[counter] + str2[counter]
counter += 1
return newStr
else:
return "The two Strings are not equal in length"
I have to do this exercise without using library function. So far I have reached here:-
string = input("Enther The String :")
substring = input("Enter the substring :")
count = 0
for i in range(len(string)):
if string[i:i+len(substring)] == substring:
if string[i+len(substring)] == ' ':
count += 1
else:
count = 0
print(count)
But, let us say if the sub-string is 'bob' and the string is 'bob cat bob cat bobs cat', the program still counts 'bob' in 'bobs' and I don't want that. Also this code always returns 0. Please help! Thanks!
the program still counts 'bob' in 'bobs'
It doesn't.
Also this code always returns 0
This is because of your else clause.
else:
count = 0
You're resetting the count here. That's not what you want; if the next character isn't a space, you don't want to do anything at all. Remove the whole else clause.
You have an additional bug you haven't noticed. If string ends with substring, the following test:
if string[i+len(substring)] == ' ':
will attempt to read past the end of the string and throw an IndexError. Try to solve this problem on your own first.
As you're allowed to use slicing, so you can use that to check whether the character before/after the substring is a space or empty string, if it is then increment count by 1. Note that slices never raise exception, even for out of range indices.
def sub_str_count(s, sub_str):
le = len(sub_str)
count = 0
for i in range(len(s)):
if s[i:i+le] == sub_str and s[i-1:i] in ('', ' ') and \
s[i+le:i+le+1] in ('', ' '):
count += 1
return count
Exception handling based version of the above code:
def check(s, ind):
"""
Check whether the item present at this index is a space or not.
For out of bound indices return True.
For negative indices return True.
"""
if ind < 0:
return True
try:
return s[ind] == ' '
except IndexError:
return True
def sub_str_count(s, sub_str):
le = len(sub_str)
count = 0
for i in range(len(s)):
if s[i:i+le] == sub_str and check(s, i-1) and check(s, i+le):
count += 1
return count
This is my simple code.
def reverseString(aStr):
newStr = ''
if len(aStr) == 0:
return newStr
else:
newStr = newStr + aStr[len(aStr)-1]
return reverseString(aStr[:len(aStr)-1])
For 'alina' (if I insert print newStr before return reverseString...), the output is: newStr='a', newStr='n', newStr='i', newStr='l', newStr='a', newStr=''. I don't get it. Why does it behave like this?
The reason your function has not worked is because you forgot to return newStr at the end. And every time you call your function, newStr will just get reset back to ''.
There's an easier way to do what you are doing. Use slicing:
def reverseString(s):
return s[::-1]
Examples:
>>> reverseString('alina')
'anila'
>>> reverseString('racecar')
'racecar' # See what I did there ;)
Something like this:
def reverseString(aStr, newStr = ''):
if len(aStr) == 0:
return newStr
else:
newStr = newStr + aStr[-1] #-1 returns the last element from the string
return reverseString(aStr[:-1], newStr) #slice the string up to second last char
print reverseString("foobar")
#raboof
The problem with your code is that newStr is getting re-assigned at each recursive loop to an empty string(''), you must pass the newStr value in every recursive call.
def reverseString(aStr, newStr= ''): #define a default value for newStr
if len(aStr) == 0:
return newStr
else:
newStr = newStr + aStr[len(aStr)-1] #better use aStr[-1]
return reverseString(aStr[:len(aStr)-1], newStr) #pass the new value of newStr
print reverseString("foobar")# No value is passed for newStr. So, default is used .
Just sayin', there's an easier way to do this, which avoids recursion and the problems that it entails :
>>> ''.join(reversed("abcd"))
'dcba'
You are returning the result of the recursive call, without keeping the information from previous calls. You have this line:
newStr = newStr + aStr[len(aStr)-1]
but newStr is then discarded.
Possible solution:
def reverseString(aStr):
if len(aStr) == 0:
return ''
else:
return aStr[-1] + reverseString(aStr[:-1])
or simply
def reverseString(s):
return s[-1]+reverseString(s[:-1]) if s else ''
Note that both these solutions are elegant, but are "normal" recursion, and therefore suboptimal; for a tail-recursive solution (which potentially can be optimized into a loop) see #Ashwini Chaudhary's answer.