Getting "string index out of range" error - python

The code is from CodingBat and the question is: Return True if the string "cat" and "dog" appear the same number of times in the given string.
I have the solution but it states that the string index is out of range. I do not really understand what this means since I am new to python.
def cat_dog(str):
dogCount = 0
catCount = 0
length = len(str)
if length > 6:
for i in range(length-1):
if str[i]== 'd' and str[i+1]== 'o' and str[i+2]== 'g':
dogCount +=1
elif str[i]== 'c' and str[i+1]== 'a' and str[i+2]== 't':
catCount +=1
else:
return False
if dogCount == catCount:
return True
else:
return False
Expect either a true or false based on the function results

String index out of range error means you're trying to access a letter beyond the length of the string. This is happening in your for loop because when i = length - 2, str[i+2] becomes str[length] which is beyond the length of the string. Also, you should change if length > 6 to if length >= 6. Try this code:
def cat_dog(string):
dogCount = 0
catCount = 0
length = len(string)
if length >= 6:
for i in range(length-2):
if string[i]== 'd' and string[i+1]== 'o' and string[i+2]== 'g':
dogCount +=1
elif string[i]== 'c' and string[i+1]== 'a' and string[i+2]== 't':
catCount +=1
else:
return False
if dogCount == catCount:
return True
else:
return False

A possible solution is to continuously check the string to see if it contains either of the words replacing the first occurrence until there is no more:
def cat_dog(string):
dogCount = 0
catCount = 0
while "dog" in string:
dogCount += 1
string = string.replace("dog", "", 1)
while "cat" in string:
catCount += 1
string = string.replace("cat", "", 1)
if dogCount == catCount:
return True
else:
return False

Related

How to understand a question about inserting occurrences? Python [duplicate]

I came across this exercise of checking whether or not the simple brackets "(", ")" in a given string are matched evenly.
I have seen examples here using the stack command which I haven't encountered yet. So I attempted a different approach. Can anyone tell me where I am going wrong?
def matched(str):
ope = []
clo = []
for i in range(0,len(str)):
l = str[i]
if l == "(":
ope = ope + ["("]
else:
if l == ")":
clo = clo + [")"]
else:
return(ope, clo)
if len(ope)==len(clo):
return True
else:
return False
The idea is to pile up "(" and ")" into two separate lists and then compare the length of the lists. I also had another version where I had appended the lists ope and clo with the relevant I which held either ( or ) respectively.
A very slightly more elegant way to do this is below. It cleans up the for loop and replaces the lists with a simple counter variable. It also returns false if the counter drops below zero so that matched(")(") will return False.
def matched(str):
count = 0
for i in str:
if i == "(":
count += 1
elif i == ")":
count -= 1
if count < 0:
return False
return count == 0
This checks whether parentheses are properly matched, not just whether there is an equal number of opening and closing parentheses. We use a list as a stack and push onto it when we encounter opening parentheses and pop from it when we encounter closing parentheses.
The main problem with your solution is that it only counts the number of parentheses but does not match them. One way of keeping track of the current depth of nesting is by pushing opening parentheses onto a stack and popping them from the stack when we encounter a closing parenthesis.
def do_parentheses_match(input_string):
s = []
balanced = True
index = 0
while index < len(input_string) and balanced:
token = input_string[index]
if token == "(":
s.append(token)
elif token == ")":
if len(s) == 0:
balanced = False
else:
s.pop()
index += 1
return balanced and len(s) == 0
My solution here works for brackets, parentheses & braces
openList = ["[", "{", "("]
closeList = ["]", "}", ")"]
def balance(myStr):
stack = []
for i in myStr:
if i in openList:
stack.append(i)
elif i in closeList:
pos = closeList.index(i)
if stack and (openList[pos] == stack[-1]):
stack.pop()
else:
return "Unbalanced"
if len(stack) == 0:
return "Balanced"
print(balance("{[()](){}}"))
Most blatant error done by you is:
if l == ")":
clo = clo + [")"]
else:
return(ope, clo) # here
By using return, you exit from function when first char not equal to "(" or ")" is encountered. Also some indentation is off.
Minimal change which allows your code to run (although it won't give correct answers for all possible input strings) is:
def matched(str):
ope = []
clo = []
for i in range(0,len(str)):
l = str[i]
if l == "(":
ope = ope + ["("]
elif l == ")":
clo = clo + [")"]
if len(ope)==len(clo):
return True
else:
return False
The problem with your approach is that you don't consider the order. Following line would pass: ))) (((.
I'd suggest to keep the count of open and closed parenthesis:
counter starts from 0
every ( symbol increments counter
every ) symbol decrements counter
if at any moment counter is negative it is an error
if at the end of the line counter is 0 - string has matching parenthesis
a = "((a+b)*c)+(b*a))"
li = list(a)
result = []
for i in range(0, len(a)):
if a[i] == "(":
result.append(i)
elif a[i] == ")":
if len(result) > 0:
result.pop()
else:
li.pop(i)
for i in range(0, len(result)):
li.pop(result[i])
print("".join(li))
this code works fine
def matched(s):
p_list=[]
for i in range(0,len(s)):
if s[i] =='(':
p_list.append('(')
elif s[i] ==')' :
if not p_list:
return False
else:
p_list.pop()
if not p_list:
return True
else:
return False
You can do this in a couple of lines using accumulate (from itertools). The idea is to compute a cumulative parenthesis level going through the string with opening parentheses counting as level+1 and closing parentheses counting as level-1. If, at any point, the accumulated level falls below zero then there is an extra closing parenthesis. If the final level is not zero, then there is a missing closing parenthesis:
from itertools import accumulate
def matched(s):
levels = list(accumulate((c=="(")-(c==")") for c in s))
return all( level >= 0 for level in levels) and levels[-1] == 0
An alternative to check for balanced nested parentheses:
def is_balanced(query: str) -> bool:
# Alternative: re.sub(r"[^()]", "", query)
query = "".join(i for i in query if i in {"(", ")"})
while "()" in query:
query = query.replace("()", "")
return not query
for stmt in [
"(()()()())", # True
"(((())))", # True
"(()((())()))", # True
"((((((())", # False
"()))", # False
"(()()))(()", # False
"foo", # True
"a or (b and (c or d)", # False
"a or (b and (c or d))" # True
"a or (b and (c or (d and e)))", # True
]:
print(stmt)
print("Balanced:", is_balanced(stmt))
print()
It works by:
Removing everything but parentheses
Recursively remove innermost parentheses pairs
If you're left with anything besides the empty string, the statement is not balanced. Otherwise, it is.
if the parenthesis sequence is not an issue (strings like )( ) this code is faster :
def matched_parenthesis(s):
return s.count('(') == s.count(')')
Tested with 15KB string, it is ~20μs v.s. 1ms iterating over the whole string.
And for me the order is not an issue as the underlying protocol guaranties that the string is well-formed.
In case u also need to find the position of the first mismatching bracket from left u can use the below code which also cover certain edge cases:
def isBalanced(expr):
opening=set('([{')
new=set(')]}{[(')
match=set([ ('(',')'), ('[',']'), ('{','}') ])
stack=[]
stackcount=[]
for i,char in enumerate(expr,1):
if char not in new:
continue
elif char in opening:
stack.append(char)
stackcount.append(i)
else:
if len(stack)==0:
print(i)
return False
lastOpen=stack.pop()
lastindex=stackcount.pop()
if (lastOpen, char) not in match:
print (i)
return False
length=len(stack)
if length!=0:
elem=stackcount[0]
print (elem)
return length==0
string =input()
ans=isBalanced(string)
if ans==True:
print("Success")
if "(" ,")" these two characters are not present then we don't want to return true or false just return no matching found. if matching found i just checking the count of both characters are same then return true, else return false
def matched(str):
count1=0
count2=1
for i in str:
if i =="(":
count1+=1:
elif i==")":
count2+=1:
else:
print "no matching found for (,)"
if count1==count2:
return True
else:
return False
Simplest of all , though all of you guys have done good:
def wellbracketed(s):
left=[]
right=[]
for i in range(0,len(s)):``
if s[i]=='(':
left=left+['(']
elif s[i]==')':
if len(left)!=0:
right=right+[')']
else:
return False
return(len(left)==len(right))
here's another way to solve it by having a counter that tracks how many open parentheses that are difference at this very moment.
this should take care all of the cases.
def matched(str):
diffCounter = 0
length = len(str)
for i in range(length):
if str[i] == '(':
diffCounter += 1
elif str[i] == ')':
diffCounter -= 1
if diffCounter == 0:
return True
else:
return False
input_str = "{[()](){}}"
strblance=""
for i in input_str:
if not strblance:
strblance = strblance+i
elif (i is '}' and strblance[len(strblance)-1] is '{') \
or ( i is']'and strblance[len(strblance)-1] is '[') \
or ( i is ')'and strblance[len(strblance)-1] is '('):
strblance = strblance[:len(strblance)-1]
else:
strblance = strblance+i
if not strblance:
print ("balanced")
else:
print ("Not balanced")
More advanced example in which you additionally need to check a matching of square brackets '[]' and braces '{}' pars.
string = '([]{})'
def group_match(string):
d = {
')':'(',
']':'[',
'}':'{'
}
list_ = []
for index, item in enumerate(string):
if item in d.values():
list_.append(item)
elif (item in d.keys()) and (d.get(item) in list_):
list_.pop()
return len(list_) == 0
The simplest code ever!!
def checkpar(x):
while len(''.join([e for e in x if e in "()"]).split('()'))>1: x=''.join(x.split('()'))
return not x
you can check this code.
This code don't use stack operations.
def matched(s):
count = 0
for i in s:
if i is "(":
count += 1
elif i is ")":
if count != 0:
count -= 1
else:
return (False)
if count == 0:
return (True)
else:
return (False)
#function to check if number of closing brackets is equal to the number of opening brackets
#this function also checks if the closing bracket appears after the opening bracket
def matched(str1):
if str1.count(")")== str1.count("("):
p1=str1.find("(")
p2=str1.find(")")
if p2 >= p1:
str1=str1[p1+1:p2]+ str1[p2+1:]
if str1.count(")")>0 and str1.count("(")>0:
matched(str1)
return True
else:
return False
else:
return False
matched(str1)
parenthesis_String = input("Enter your parenthesis string")
parenthesis_List = []
for p in parenthesis_String:
parenthesis_List.append(p)
print(parenthesis_List)
if len(parenthesis_List)%2 != 0:
print("Not Balanced Wrong number of input")
for p1 in parenthesis_List:
last_parenthesis = parenthesis_List.pop()
print(last_parenthesis)
if (p1 == '{' and last_parenthesis == '}' or p1 == '[' and last_parenthesis == ']' or p1 == '(' and last_parenthesis == ')'):
print("Balanced")
else:
print("Not balanced")
A little different one.
expression = '{(){({)}}'
brackets = '[](){}'
stack = []
balanced = False
for e in expression:
if e in brackets and stack: # Popping from the stack if it is closing bracket
if stack [-1] == brackets[brackets.index(e)-1]:
stack.pop()
balanced = True
continue # it will go to the new iteration skipping the next if below
if e in brackets: # Push to stack if new bracket in the expression
stack .append(e)
balanced = False
balanced = 'Balanced' if balanced and not stack else 'Unbalanced'
print(balanced, stack)
just modified Henry Prickett-Morgan's code a little bit to handle it more sensibly, namely taking into account that the number of "(" matches that of ")" but string starts with ")" or ends with "(" which are apparently not right.
def ValidParenthesis(s):
count = 0
if s[0] == ')' or s[-1] == '(':
return False
else:
for c in s:
if c == '(':
count += 1
elif c == ')':
count -= 1
else:
continue
return count == 0
The best way to understand this snippet is to follow along with all kind of scenarios.
in_data = ['{','[','(']
out_data = ['}',']',')']
def check_match(statements):
stack = []
for ch in statements:
if ch in in_data:
stack.append(ch)
if ch in out_data:
last = None
if stack:
last = stack.pop()
if last is '{' and ch is '}':
continue
elif last is '[' and ch is ']':
continue
elif last is '(' and ch is ')':
continue
else:
return False
if len(stack) > 0:
return False
else:
return True
print(check_match("{www[eee}ee)eee"))
print(check_match("(ee)(eee[eeew]www)"))
print(check_match("(ss(ss[{ss}]zs)zss)"))
print(check_match("([{[[]]}])"))
def matched(str):
braces = {"{": "}", "(": ")", "[": "]"}
stack = []
for c in str:
if c in braces.keys():
stack.append(c)
elif c in braces.values():
if not stack:
return False
last_brace = stack.pop()
if braces[last_brace] != c:
return False
if stack:
return False
return True
print(matched("()"))
>> True
print(matched("(}"))
>> False
print(matched("}{"))
>> False
print(matched("}"))
>> False
print(matched("{"))
>> False
print(matched("(ff{fgg} [gg]h)"))
>> True
Given a string s containing just the characters '(', ')', '{', '}', '[' and ']',
determine if the input string is valid.
def isValid(s):
stack = []
for i in s:
if i in open_list:
stack.append(i)
elif i in close_list:
pos = close_list.index(i)
if open_list[pos] == stack[len(stack)-1]:
stack.pop()
else:
return False
if len(stack) == 0:
return True
else:
return False
print(isValid("{[(){}]}"))
s='{[]{()}}}{'
t=list(s)
cntc=0
cnts=0
cntp=0
cntc=min(t.count("{"),t.count("}"))
cnts=min(t.count("["),t.count("]"))
cntp=min(t.count("("),t.count(")"))
print(cntc+cnts+cntp)
for a balanced string, we can find an opening brace followed by it closing brace. if you do this basic check you could remove the checked substring and check the remaining string. At the end, if the string is not empty then it is not balanced.
def is_balanced(s: str) -> bool:
while any([x in s for x in ["", "", ""]]):
s=s.replace("{}", "").replace("[]","").replace("()","")
return s==""
def parenthesis_check(parenthesis):
chars = []
matches = {')':'(',']':'[','}':'{'}
for i in parenthesis:
if i in matches:
if chars.pop() != matches[i]:
return False
else:
chars.append(i)
return chars == []
foo1="()()())("
def bracket(foo1):
count = 0
for i in foo1:
if i == "(":
count += 1
else:
if count==0 and i ==")":
return False
count -= 1
if count == 0:
return True
else:
return False
bracket(foo1)
Although I'm not proposing a fix to your implementation, I suggest a cleaner and more pythonic version of the #kreld solution:
def check_parentheses(expr):
s = []
for c in expr:
if c in '(':
s.append(c)
elif c in ')':
if not len(s):
break
else:
s.pop()
else:
return not len(s)
return False
# test -----------------------------------------------------------------
test_expr = [')(', '(()', '())', '(', ')', '((', '))', '(()())', '(())',
'()', '()(())']
for i, t in enumerate(test_expr, 1):
print '%i\t%s\t%s' % (i, t, check_parentheses(t))
# output ---------------------------------------------------------------
1 )( False
2 (() False
3 ()) False
4 ( False
5 ) False
6 (( False
7 )) False
8 (()()) True
9 (()) True
10 () True
11 ()(()) True

Finding a 'hello' word in a different string, which it has 'hello' in it(additional)

Finding a 'hello' word in a different string, which it has 'hello' in it
I should find a 'hello' word in a string, which I gave it from input too .I wrote this code by looking at the answer that someone gave to the below link's question.
firststring = input() #ahhellllloou
to_find = "hello"
def check_string(firststring, to_find):
c = 0
for i in firststring:
#print(i)
if i == to_find[c]:
c += 1
if c == len(to_find):
return "YES"
return "NO"
print(check_string(firststring, to_find))
but I don't want to use a def to solve the problem.
hello = "hello"
counter_hello = 0
bool_hello = False
for letter in string:
if letter == hello[counter_hello]:
counter_hello += 1
if counter_hello == len(hello):
bool_hello = True
if bool_hello == True:
print("YES")
else:
print("NO")
for hello string it works correct. also for pnnepelqomhhheollvlo.
but when I give it ahhellllloou it doesn't work.
I can't see where the bug is.
Your code is not the same. The return statement needs to be accounted for by breaking the loop
string = "ahhellllloou"
to_find = "hello"
match = False
c = 0
for i in string:
if i == to_find[c]:
c += 1
if c == len(to_find):
match = True
break
print("YES" if match else "NO")
Note that a loop isn't needed
>>> import re
>>> m = re.search('.*'.join('hello'), 'ahhellllloou')
>>> m is not None
True
>>> m = re.search('.*'.join('hello'), 'ahhellllliu')
>>> m is None
True
counter_hello = 0
bool_hello = False
for letter in 'ahhellllloou':
#print('letter: ', letter);
#print(hello[counter_hello])
if letter == hello[counter_hello] and counter_hello != len(hello) - 1:
counter_hello += 1
if counter_hello == len(hello) - 1:
bool_hello = True
if bool_hello == True:
print("YES")
else:
print("NO")

Function containing exactly one of each of the 5 vowels

I'm trying to create a function to evaluate if contains exactly one of each of the 5 vowels.
I've tried so far: (I don't know how can I limit now for only 1 of each vowel)
def isVowel(char): #=> Helper function
return len(char) == 1 and char.lower() in 'aeiou'
def fiveVowelsOneOfEach(word):
oneVowelOfEachCounter = 0
for char in word:
if isVowel(char):
if char == 'a':
oneVowelOfEachCounter += 1
if char == 'e':
oneVowelOfEachCounter += 1
if char == 'i':
oneVowelOfEachCounter += 1
if char == 'o':
oneVowelOfEachCounter += 1
if char == 'u':
oneVowelOfEachCounter += 1
if oneVowelOfEachCounter == 5:
return True
Just do:
s = 'aeiou'
s2 = 'aaeiou'
def checker(s):
return all(s.lower().count(i)==1 for i in 'aeiou')
print(checker(s))
print(checker(s2))
Output:
True
False
That's all needed, checking if the counts of each vowel is one
A simpler way of doing it
goodstr = 'aeiou'
badstr = 'aaeiou'
vowels = ['a','e','i','o','u'] # or a string "aeiou"
def fiveVowelsIsOneOfEach(word):
for vowel in vowels:
if word.count(vowel) != 1:
return False
return True
print(fiveVowelsIsOneOfEach(goodstr)) # returns True
print(fiveVowelsIsOneOfEach(badstr)) # returns False
def fiveVowelsOneOfEach(word):
oneVowelOfEachCounter = 0
vowels = list('aeiou')
dummy_vowels = list(chars)
for char in word:
if char in vowels:
vowels.remove(char)
continue
elif char in dummy_vowels:
return False
if len(vowels) == 0:
return True
return False
This should work. the trick is to use a list and a dummy list to make sure each vowel is only counted once.
Updated answer to address the issues in the question. Also added a version that does not use counter.
from collections import Counter
word = 'aaeiuo'
vowels = 'aeiuo'
c = Counter(word)
vowel_count = sum([1 if c[vowel] > 0 else 0 for vowel in vowels])
print(vowel_count) # 5
#without using counter
vowel_count = sum([1 if word.count(vowel) > 0 else 0 for vowel in vowels])
print(vowel_count) # 5

Python Recursion Double letters

So what the task is, is that your supposed to write a recursion function that counts the amount of "double" letters in a string, So for example the string "hmmm" would return 1 and the string "hmmmm" would return 2 and that a string "abb" would return 1. My code is here:
def num_double_letters(astr):
if astr == "" or len(astr) == 1:
return 0
elif len(astr) == 2:
if astr[0] == astr[1]:
return 1 + num_double_letters(astr[1:])
else:
return 0 + num_double_letters(astr[1:])
elif astr[0] != astr[1]:
return 0 + num_double_letters(astr[1:])
elif astr[0] == astr[1] != astr[2]:
return 1 + num_double_letters(astr[1:])
elif astr[0] == astr[1] == astr[2]:
return 0 + num_double_letters(astr[1:])
My problem is that a string with 4 same letters = 1 when its supposed to = 2. And also is there a cleaner way to do this?
I think you've made it a bit complicated for yourself... there's no need to go deeper into the recursion once the length of your string is 2, and you want to advance by 2, not 1 when you find a double to count the way I think you do. Try this:
def num_double_letters(astr):
if astr == "" or len(astr) == 1:
return 0
elif len(astr) == 2:
if astr[0] == astr[1]:
return 1
else:
return 0
elif astr[0] != astr[1]:
return 0 + num_double_letters(astr[1:])
elif astr[0] == astr[1]:
return 1 + num_double_letters(astr[2:])
print(num_double_letters('hmm'))
print(num_double_letters('hmmm'))
print(num_double_letters('hmmmm'))
Output:
1
1
2
You might consider the following more Pythonic and concise:
def num_double_letters(astr):
if len(astr) < 2:
return 0
if astr[0] == astr[1]:
return 1 + num_double_letters(astr[2:])
return num_double_letters(astr[1:])

Given a String, What is the Length of the One of the Longest WFF in Polish Notation?

I'm trying to write a version of always popular Count-A-WFF section of the WFF 'N Proof game (no copyright infringement intended) in Python. Alright, not so popular.
I think I have everything up and running up as desired for up to the case of a 4 letter string.
def maximum_string(s):
if cs(s) == True:
return len(s)
elif len(s) == 2:
l1 = [cs(s[0]), cs(s[1])]
if True in l1:
return len(s) - 1
else:
return 0
elif len(s) == 3:
first = s[0] + s[1]
second = s[0] + s[2]
third = s[1] + s[2]
l1 = [cs(first), cs(second), cs(third)]
if True in l1:
return len(s) - 1
l2 = [cs(s[0]), cs(s[1]), cs(s[2])]
if True in l2:
return len(s) - 2
else:
return 0
elif len(s) == 4:
first = s[0]+s[1]+s[2]
second = s[0]+s[1]+s[3]
third = s[1]+s[2]+s[3]
fourth = s[0]+s[2]+s[3]
l1 = [cs(first), cs(second), cs(third), cs(fourth)]
if True in l1:
return 3
first = s[0] + s[1]
second = s[0] + s[2]
third = s[0] + s[3]
fourth = s[1] + s[2]
fifth = s[1] + s[3]
sixth = s[2] + s[3]
l2 = [cs(first), cs(second), cs(third), cs(fourth), cs(fifth), cs(sixth)]
if True in l2:
return 2
first = s[0]
second = s[1]
third = s[2]
fourth = s[3]
l3 = [cs(first), cs(second), cs(third), cs(fourth)]
if True in l3:
return 1
else:
return 0
def cs(string):
global length_counter, counter, letter
counter = 1
length_counter = 0
letters_left = len(string)
while letters_left != 0 and length_counter < len(string):
letter = string[length_counter]
if letter == 'C' or letter == 'A' or letter == 'K' or letter == 'E' or letter == "K":
counter += 1
elif letter == 'N':
counter += 0
else:
counter -= 1
length_counter += 1
letters_left -= 1
if counter == 0 and len(string) == length_counter:
return True
else:
return False
The maximum_string helper function is intended to, given any string S, find the length of one of the longest possible wffs that you can make from just the letters of S. Of course, I can continue the pattern I currently have for the maximum_string helper function up to a length of 13. But, combinatorial explosion is evident. Thus, is there a more elegant way to finish off the maximum string helper function?
In effect one of the functions I had earlier would return a distance of how far away a string is from having a permutation in Polish notation. Thus this was surprisingly simpler to fix than I expected. Here's what I was looking for:
def maximum_string(string):
global length_counter, counter, letter
counter = 1
length_counter = 0
letters_left = len(string)
while letters_left != 0 and length_counter < len(string):
letter = string[length_counter]
if letter == 'C' or letter == 'A' or letter == 'K' or letter == 'E' or letter == "K":
counter += 1
elif letter == 'N':
counter += 0
else:
counter -= 1
length_counter += 1
letters_left -= 1
if ('p' in string) or ('q' in string) or ('r' in string) or ('s' in string) or ('t' in string) or ('u' in string):
return len(string) - abs(counter)
else:
return 0

Categories

Resources