Counting while using recursion with strings from inputs - python

I'm trying to create a game where the score is dependent on what the letters are worth. I'm having trouble with keeping a count on the side while still recursing to the next letter of the string. I'm really stuck & I hope you can help!
def net_zero():
guess_prompt = input('Guess a string: ')
win_display = 'Congratulations you win'
low_vowels = "aeiou" # +1
low_constants = "bcdfghjklmnpqrstvwxyz" # -1
up_vowels = "AEIOU" # +2
up_constants = "BCDFGHJKLMNPQRSTVWXYZ" # -2
ten_digits = "0123456789" # +3
#else -3
count = 0
if len(guess_prompt) == 0:
return count
elif guess_prompt[0] in low_vowels:
return (count + 1) + guess_prompt[1:]
elif guess_prompt[0] in low_constants:
return (count - 1) + guess_prompt[1:]
elif guess_prompt[0] in up_vowels:
return (count + 2) + guess_prompt[1:]
elif guess_prompt[0] in up_constants:
return (count - 2) + guess_prompt[1:]
elif guess_prompt[0] in ten_digits:
return (count + 3) + guess_prompt[1:]
else: return (count - 3) + guess_prompt[1:]

I think you would like to do following
count = 0
if len(guess_prompt) == 0:
return count
for letter in guess_prompt:
if letter in low_vowels:
count +=1
if letter in low_constants:
count -=1
...
return count

I feel you can use dict instead of using string content for lookup. It will improve lookup time.
guess_prompt = "aaB4??BBBBB"
value = {}
for char in "aeiou":
value[char] = 1
for char in "bcdfghjklmnpqrstvwxyz":
value[char] = -1
for char in "AEIOU":
value[char] = 2
for char in "BCDFGHJKLMNPQRSTVWXYZ":
value[char] = -2
for char in "0123456789":
value[char] = 3
count = 0
for char in guess_prompt:
count = count + value.get(char, -3) #default value -3
print(count) ## PRINTS -13 ##

Related

Getting a 'list index out of range' error

The goal of this code is to find the number of 'sh', 'th', 'wh', and 'ch' digraphs there are in any given sentence. The function keeps returning a 'list index out of range' error, when it seems like everything should be running properly.
exsentence = input("Enter a sentence to scan: ")
slist = list(exsentence.lower())
ch = 0
sh = 0
th = 0
wh = 0
i = 0
'''muppets = slist[i] + slist[i+1]'''
while i < len(slist):
if slist[i] + slist[i+1] == "sh":
sh += 1
elif slist[i] + slist[i+1] == "ch":
ch += 1
elif slist[i] + slist[i+1] == "th":
th += 1
else:
if slist[i] + slist[i+1] == "wh":
wh += 1
i+=1
print("Has {} 'ch' {} 'sh' {} 'th' {} 'wh'".format(ch,sh,th,wh))
Any help is very appriceciated. Thank you.
i+1 will be out of slist bounds. You need to iterate until slist size - 1
while i < len(slist) - 1:
As a side note, for seems to be more appropriate here. Remove i = 0 and i+=1
for i in range(len(slist) - 1):
Use a for loop with range instead:
exsentence = input("Enter a sentence to scan: ")
slist = list(exsentence.lower())
ch = 0
sh = 0
th = 0
wh = 0
i = 0
'''muppets = slist[i] + slist[i+1]'''
for i in range(1,len(slist)):
if slist[i-1] + slist[i] == "sh":
sh += 1
elif slist[i-1] + slist[i] == "ch":
ch += 1
elif slist[i-1] + slist[i] == "th":
th += 1
elif slist[i-1] + slist[i] == "wh":
wh += 1
print(f"Has {ch} 'ch' {sh} 'sh' {th} 'th' {wh} 'wh'")
start the range at 1 and check i-1 against i this way you wont go out of index range
You are checking one position ahead of the current one. Thus you are getting the error of being out of range.
Basically, you are iterating over each position of the array, but you are checking for the nth position against the nth + 1 position. What does happen when you reach the last position? You check it with the next position, which is not defined (otherwise it would not be the last position), and thus get the out of range error.
My suggestion is to not perform the check on the last item against the next one, as there will not be any sequence anymore.
while i < len(slist) - 1:
if slist[i] + slist[i+1] == "sh":
sh += 1
elif slist[i] + slist[i+1] == "ch":
ch += 1
elif slist[i] + slist[i+1] == "th":
th += 1
else:
if slist[i] + slist[i+1] == "wh":
wh += 1
i+=1

how to decrease time complexity in python?

Given a paragraph of space-separated lowercase English words and a list of unique lowercase English keywords, find the minimum length of the substring of which contains all the keywords that are separated by space in any order.
i put the following code where is the error ? How can i decrease time complexity.
import sys
def minimumLength(text, keys):
answer = 10000000
text += " $"
for i in xrange(len(text) - 1):
dup = list(keys)
word = ""
if i > 0 and text[i - 1] != ' ':
continue
for j in xrange(i, len(text)):
if text[j] == ' ':
for k in xrange(len(dup)):
if dup[k] == word:
del(dup[k])
break
word = ""
else:
word += text[j]
if not dup:
answer = min(answer, j - i)
break
if(answer == 10000000):
answer = -1
return answer
text = raw_input()
keyWords = int(raw_input())
keys = []
for i in xrange(keyWords):
keys.append(raw_input())
print(minimumLength(text, keys))
The trick is to scan from left to right and, once you find a window containing all the keys, try to reduce it on the left and enlarge it on the right preserving the property that all the terms remain inside the window.
Using this strategy you can solve the task in linear time.
The following code is a draft of the code that I tested on few strings, I hope the comments are enough to highlight the most critical steps:
def minimum_length(text, keys):
assert isinstance(text, str) and (isinstance(keys, set) or len(keys) == len(set(keys)))
minimum_length = None
key_to_occ = dict((k, 0) for k in keys)
text_words = [word if word in key_to_occ else None for word in text.split()]
missing_words = len(keys)
left_pos, last_right_pos = 0, 0
# find an interval with all the keys
for right_pos, right_word in enumerate(text_words):
if right_word is None:
continue
key_to_occ[right_word] += 1
occ_word = key_to_occ[right_word]
if occ_word == 1: # the first time we see this word in the current interval
missing_words -= 1
if missing_words == 0: # we saw all the words in this interval
key_to_occ[right_word] -= 1
last_right_pos = right_pos
break
if missing_words > 0:
return None
# reduce the interval on the left and enlarge it on the right preserving the property that all the keys are inside
for right_pos in xrange(last_right_pos, len(text_words)):
right_word = text_words[right_pos]
if right_word is None:
continue
key_to_occ[right_word] += 1
while left_pos < right_pos: # let's try to reduce the interval on the left
left_word = text_words[left_pos]
if left_word is None:
left_pos += 1
continue
if key_to_occ[left_word] == 1: # reduce the interval only if it doesn't decrease the number of occurrences
interval_size = right_pos + 1 - left_pos
if minimum_length is None or interval_size < minimum_length:
minimum_length = interval_size
break
else:
left_pos += 1
key_to_occ[left_word] -= 1
return minimum_length

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

Binary Subtraction - Python

I want to make a binary calculator and I have a problem with the subtraction part. Here is my code (I have tried to adapt one for sum that I've found on this website).
maxlen = max(len(s1), len(s2))
s1 = s1.zfill(maxlen)
s2 = s2.zfill(maxlen)
result = ''
carry = 0
i = maxlen - 1
while(i >= 0):
s = int(s1[i]) - int(s2[i])
if s <= 0:
if carry == 0 and s != 0:
carry = 1
result = result + "1"
else:
result = result + "0"
else:
if carry == 1:
result = result + "0"
carry = 0
else:
result = result + "1"
i = i - 1
if carry>0:
result = result + "1"
return result[::-1]
The program works fine with some binaries subtraction but it fails with others.
Can someone please help me because I can't find the mistake? Thanks a lot.
Short answer: Your code is wrong for the case when s1[i] == s2[i] and carry == 1.
Longer answer: You should restructure your code to have three separate cases for s==-1, s==0, and s==1, and then branch on the value of carry within each case:
if s == -1: # 0-1
if carry == 0:
...
else:
...
elif s == 0: # 1-1 or 0-0
if carry == 0:
...
else:
...
else: # 1-0
if carry == 0:
...
else:
...
This way you have a separate block for each possibility, so there is no chance of overlooking a case like you did on your first attempt.
I hope the answer below it helps.
def binarySubstration(str1,str2):
if len(str1) == 0:
return
if len(str2) == 0:
return
str1,str2 = normaliseString(str1,str2)
startIdx = 0
endIdx = len(str1) - 1
carry = [0] * len(str1)
result = ''
while endIdx >= startIdx:
x = int(str1[endIdx])
y = int(str2[endIdx])
sub = (carry[endIdx] + x) - y
if sub == -1:
result += '1'
carry[endIdx-1] = -1
elif sub == 1:
result += '1'
elif sub == 0:
result += '0'
else:
raise Exception('Error')
endIdx -= 1
return result[::-1]
normalising the strings
def normaliseString(str1,str2):
diff = abs((len(str1) - len(str2)))
if diff != 0:
if len(str1) < len(str2):
str1 = ('0' * diff) + str1
else:
str2 = ('0' * diff) + str2
return [str1,str2]

Index Error When Comparing Strings - Python

I am having a bit of trouble with some Python code. I have a large text file called "big.txt". I have iterated over it in my code to sort each word into an array (or list) and then iterated over it again to remove any character that is not in the alphabet. I also have a function called worddistance which looks at how similar two words are and returns a score subsequently. I have another function called autocorrect. I want to pass this function a misspelled word, and print a 'Did you mean...' sentence with words that gave a low score on the worddistance function (the function adds 1 to a counter whenever a difference is noticed - the lower the score, the more similar).
Strangely, I keep getting the error:
"Index Error: string index out of range"
I am at a loss at what is going on!
My code is below.
Thanks in advance for the replies,
Samuel Naughton
f = open("big.txt", "r")
words = list()
temp_words = list()
for line in f:
for word in line.split():
temp_words.append(word.lower())
allowed_characters = 'abcdefghijklmnopqrstuvwxyz'
for item in temp_words:
temp_new_word = ''
for char in item:
if char in allowed_characters:
temp_new_word += char
else:
continue
words.append(temp_new_word)
list(set(words)).sort()
def worddistance(word1, word2):
counter = 0
if len(word1) > len(word2):
counter += len(word1) - len(word2)
new_word1 = word1[:len(word2) + 1]
for char in range(0, len(word2) + 1) :
if word2[char] != new_word1[char]:
counter += 1
else:
continue
elif len(word2) > len(word1):
counter += len(word2) - len(word1)
new_word2 = word2[:len(word1) + 1]
for char in range(0, len(word1) + 1):
if word1[char] != word2[char]:
counter += 1
else:
continue
return counter
def autocorrect(word):
word.lower()
if word in words:
print("The spelling is correct.")
return
else:
suggestions = list()
for item in words:
diff = worddistance(word, item)
if diff == 1:
suggestions.append(item)
print("Did you mean: ", end = ' ')
if len(suggestions) == 1:
print(suggestions[0])
return
else:
for i in range(0, len(suggestions)):
if i == len(suggestons) - 1:
print("or " + suggestions[i] + "?")
return
print(suggestions[i] + ", ", end="")
return
In worddistance(), it looks like for char in range(0, len(word1) + 1): should be:
for char in range(len(word1)):
And for char in range(0, len(word2) + 1) : should be:
for char in range(len(word2)):
And by the way, list(set(words)).sort() is sorting a temporary list, which is probably not what you want. It should be:
words = sorted(set(words))
As mentioned in the other comment, you should range(len(word1)).
In addition to that:
- You should consider case where word1 and words have the same length #len(word2) == len(word1)
- You should also take care of naming. In the second condition in wordDistance function
if word1[char] != word2[char]:
You should be comparing to new_word2
if word1[char] != new_word2[char]:
- In the autocorrect, you should assign lower to word= word.lower()
words= []
for item in temp_words:
temp_new_word = ''
for char in item:
if char in allowed_characters:
temp_new_word += char
else:
continue
words.append(temp_new_word)
words= sorted(set(words))
def worddistance(word1, word2):
counter = 0
if len(word1) > len(word2):
counter += len(word1) - len(word2)
new_word1 = word1[:len(word2) + 1]
for char in range(len(word2)) :
if word2[char] != new_word1[char]:
counter += 1
elif len(word2) > len(word1):
counter += len(word2) - len(word1)
new_word2 = word2[:len(word1) + 1]
for char in range(len(word1)):
if word1[char] != new_word2[char]: #This is a problem
counter += 1
else: #len(word2) == len(word1) #You missed this case
for char in range(len(word1)):
if word1[char] != word2[char]:
counter += 1
return counter
def autocorrect(word):
word= word.lower() #This is a problem
if word in words:
print("The spelling is correct.")
else:
suggestions = list()
for item in words:
diff = worddistance(word, item)
print diff
if diff == 1:
suggestions.append(item)
print("Did you mean: ")
if len(suggestions) == 1:
print(suggestions[0])
else:
for i in range(len(suggestions)):
if i == len(suggestons) - 1:
print("or " + suggestions[i] + "?")
print(suggestions[i] + ", ")
Next time, Try to use Python built-in function like enumerate, to avoid using for i in range(list), then list[i], len instead of counter .. etc
Eg:
Your distance function could be written this way, or much more simpler.
def distance(word1, word2):
counter= max(len(word1),len(word2))- min(len(word1),len(word2))
if len(word1) > len(word2):
counter+= len([x for x,z in zip (list(word2), list(word1[:len(word2) + 1])) if x!=z])
elif len(word2) > len(word1):
counter+= len([x for x,z in zip (list(word1), list(word2[:len(word1) + 1])) if x!=z])
else:
counter+= len([x for x,z in zip (list(word1), list(word2)) if x!=z])
return counter

Categories

Resources