String index out of range in for each loop - python

My code glitches at the point its learning a letter in the code
while not cracked:
Word = "" # Word auto generates to learn a word
for element in range(0, len(WordLearning)):
print(element)
if(element in LettersItKnows):
Word = Word + WordLearning[element]
else:
if(Word[element] == WordLearning[element]): # Right Here it is weird
LettersItKnows.append(element)
else:
Word = Word + random.choice(Letters) ```

The problem here is that len() returns the number of elements in a list. but when you're getting an element from a list like this: myList[3] the first element is 0 which means that you need to do this:
while not cracked:
Word = "" # Word auto generates to learn a word
for element in range(len(WordLearning) - 1):
print(element)
if(element in LettersItKnows):
Word = Word + WordLearning[element]
else:
if(Word[element] == WordLearning[element]): # Right Here it is weird
LettersItKnows.append(element)
else:
Word = Word + random.choice(Letters) ```
You can see that all I did here was replace this: range(0, len(WordLearning)) by this: range(len(WordLearning) - 1) I got rid of the 0, because the range() starts on zero by default
Note that in this script if you reach this line: if(Word[element] == ... you'll get might get an error because there is a chance that the Word variable will still equal this: "" so you might fix that problem by setting Word to something that has more letters than the number of elements in the WordLearning variable. I can't really help you though because I don't understand anything about your script

This code will fail as soon as an character not in LettersItKnows is found, because the length of Word will then be equal to element, so Word[element], the element + 1th element of Word, will not exist.

Related

Why is my function to find the smallest word in an array not working?

I am writing a program to print out the smallest word in phrase. The output is supposed to give me the word "I" but it is instead printing out the word "am". How can I fix this? Please help, I am new to Python
#Given a string 'phrase' consisting of some words separated
# by some number of spaces, return the
# smallest word in the string.
def word_length(phrase):
splitphrase = phrase.split(" ")
min_word = ''
for i, element in enumerate(splitphrase):
if i < len(splitphrase)-1 and (len(element) <= len((splitphrase[i+1]))):
min_word = element
print(min_word)
word_length("hello I am Sam and am tall")
I'll put my code down below and then explain the changes I made:
def word_length(phrase):
splitphrase = phrase.split(" ")
min_word = splitphrase[0] #setting default value as first word
for element in (splitphrase): #for each word in the list
if len(element) < len(min_word): #if the word is shorter than our current min_word
min_word = element #redefine min_word if the current word is shorter
print(min_word)
word_length("hello I am Sam and am tall")
Output:
I
Similar to your code, we start by using the split() function to break our sentence up into words in a list.
To start finding the smallest word, we can define our min_word to initially be splitphrase[0] as our default value.
To determine if other words in the list are min_word, while iterating through every word in the list, if the length of the word we are iterating through in our list is less than the length of current min_word, we redefine min_word to be that current element.
I hope this helped! Let me know if you need any further help or clarification!
the maximum word length possible is the length of the sentence
I check that each word is smaller than the maximum length
if it is smaller I reassign the value of min_word and the min_word_length
def word_length(phrase):
splitphrase = phrase.split(" ")
max_word_lenght = len(phrase)
for el in splitphrase:
if len(el) <= max_word_lenght:
max_word_lenght = len(el)
min_word = el
print(min_word)
word_length("hello I am Sam and am tall")
If you are new to python I would recommend learning a debugging tool so you can better understand the flow of your program.
If you use the command line a possibility is PDB (https://realpython.com/python-debugging-pdb/).
If you use IDE (Spyder, VS, PyTorch) they should have a debugger built-in
How about like this:
def word_length(phrase):
sw = (words := phrase.split())[0]
for word in words[1:]:
if len(word) < len(sw):
sw = word
return sw
print(word_length("hello I am Sam and am tall"))
Note:
This will fail if phrase is an empty string or None. You will also need Python 3.8+
This code, just checks each word if its length if less than the previous shortest words length.
def word_length(phrase):
splitphrase = phrase.split(" ") # Split the phrase into each individual word
min_word = splitphrase[0] # Store the shortest word we've found yet
for element in splitphrase: # Iterate over every word
if len(element) < len(min_word): # Check if we haven't already set the min_word or this word is smaller than the current min_word
min_word = element # Set min_word to the new shortest word
print(min_word)
word_length('Hello how is it going today') # > is

Reverse a specific word function

I'm having trouble doing the next task:
So basically, I need to build a function that receives a (sentence, word, occurrence)
and it will search for that word and reverse it only where it occurs
for example:
function("Dani likes bananas, Dani also likes apples", "lik", "2")
returns: "Dani likes bananas, Dani also kiles apples"
As you can see, the "word" is 'lik' and at the second time it occurred it reversed to 'kil'.
I wrote something but it's too messy and that part still doesn't work for me,
def q2(sentence, word, occurrence):
count = 0
reSentence = ''
reWord = ''
for char in word:
if sentence.find(word) == -1:
print('could not find the word')
break
for letter in sentence:
if char == letter:
if word != reWord:
reWord += char
reSentence += letter
break
elif word == reWord:
if count == int(occurrence):
reWord = word[::-1]
reSentence += reWord
elif count > int(occurrence):
print("no such occurrence")
else:
count += 1
else:
reSentence += letter
print(reSentence)
sentence = 'Dani likes bananas, Dani also likes apples'
word = 'li'
occurrence = '2'
q2(sentence,word,occurrence)
the main problem right now is that, after it breaks it goes back to check from the start of the sentence so it will find i in "Dani". I couldn't think of a way to make it check from where it stopped.
I tried using enumerate but still had no idea how.
This will work for the given scenario
scentence = 'Dani likes bananas, Dani also likes apples'
word = 'lik'
st = word
occ = 2
lt = scentence.split(word)
op = ''
if (len(lt) > 1):
for i,x in enumerate(lt[:-1]):
if (i+1) == occ:
word = ''.join(reversed(word))
op = op + x + word
word = st
print(op+lt[-1])
Please test yourself for other scenario
This line for i,x in enumerate(lt[:-1]) basically loops on the list excluding the last element. using enumerate we can get index of the element in the list in i and value of element in x. So when code gets loops through it I re-join the split list with same word by which I broke, but I change the word on the specified position where you desired. The reason to exclude the last element while looping is because inside loop there is addition of word and after each list of element and if I include the whole list there will be extra word at the end. Hope it explains.
Your approach shows that you've clearly thought about the problem and are using the means you know well enough to solve it. However, your code has a few too many issue to simply fix, for example:
you only check for occurrence of the word once you're inside the loop;
you loop over the entire sentence for each letter in the word;
you only compare a character at a time, and make some mistakes in keeping track of how much you've matched so far.
you pass a string '2', which you intend to use as a number 2
All of that and other problems can be fixed, but you would do well to use what the language gives you. Your task breaks down into:
find the n-th occurrence of a substring in a string
replace it with another word where found and return the string
Note that you're not really looking for a 'word' per se, as your example shows you replacing only part of a word (i.e. 'lik') and a 'word' is commonly understood to mean a whole word between word boundaries.
def q2(sentence, word, occurrence):
# the first bit
position = 0
count = 0
while count < occurrence:
position = sentence.find(word, position+1)
count += 1
if position == -1:
print (f'Word "{word}" does not appear {occurrence} times in "{sentence}"')
return None
# and then using what was found for a result
return sentence[0:position] + word[::-1] + sentence[position+len(word):]
print(q2('Dani likes bananas, Dani also likes apples','lik',2))
print(q2('Dani likes bananas, Dani also likes apples','nope',2))
A bit of explanation on that return statement:
sentence[0:position] gets sentence from the start 0 to the character just before position, this is called a 'slice'
word[::-1] get word from start to end, but going in reverse -1. Leaving out the values in the slice implies 'from one end to the other'
sentence[position+len(word):] gets sentence from the position position + len(word), which is the character after the found word, until the end (no index, so taking everything).
All those combined is the result you need.
Note that the function returns None if it can't find the word the right number of times - that may not be what is needed in your case.
import re
from itertools import islice
s = "Dani likes bananas, Dani also likes apples"
t = "lik"
n = 2
x = re.finditer(t, s)
try:
i = next(islice(x, n - 1, n)).start()
except StopIteration:
i = -1
if i >= 0:
y = s[i: i + len(t)][::-1]
print(f"{s[:i]}{y}{s[i + len(t):]}")
else:
print(s)
Finds the 2nd starting index (if exists) using Regex. May require two passes in the worst case over string s, one to find the index, one to form the output. This can also be done in one pass using two pointers, but I'll leave that to you. From what I see, no one has offered a solution yet that does in one pass.
index = Find index of nth occurence
Use slice notation to get part you are interested in (you have it's beginning and length)
Reverse it
Construct your result string:
result = sentence[:index] + reversed part + sentence[index+len(word):]

Binary Search using a for loop, searching for words in a list and comparing

I'm trying to compare the words in "alice_list" to "dictionary_list", and if a word isnt found in the "dictionary_list" to print it and say it is probably misspelled. I'm having issues where its not printing anything if its not found, maybe you guys could help me out. I have the "alice_list" being appended to uppercase, as the "dictionary_list" is all in capitals. Any help with why its not working would be appreciated as I'm about to pull my hair out over it!
import re
# This function takes in a line of text and returns
# a list of words in the line.
def split_line(line):
return re.findall('[A-Za-z]+(?:\'[A-Za-z]+)?', line)
# --- Read in a file from disk and put it in an array.
dictionary_list = []
alice_list = []
misspelled_words = []
for line in open("dictionary.txt"):
line = line.strip()
dictionary_list.extend(split_line(line))
for line in open("AliceInWonderLand200.txt"):
line = line.strip()
alice_list.extend(split_line(line.upper()))
def searching(word, wordList):
first = 0
last = len(wordList) - 1
found = False
while first <= last and not found:
middle = (first + last)//2
if wordList[middle] == word:
found = True
else:
if word < wordList[middle]:
last = middle - 1
else:
first = middle + 1
return found
for word in alice_list:
searching(word, dictionary_list)
--------- EDITED CODE THAT WORKED ----------
Updated a few things if anyone has the same issue, and used "for word not in" to double check what was being outputted in the search.
"""-----Binary Search-----"""
# search for word, if the word is searched higher than list length, print
words = alice_list
for word in alice_list:
first = 0
last = len(dictionary_list) - 1
found = False
while first <= last and not found:
middle = (first + last) // 2
if dictionary_list[middle] == word:
found = True
else:
if word < dictionary_list[middle]:
last = middle - 1
else:
first = middle + 1
if word > dictionary_list[last]:
print("NEW:", word)
# checking to make sure words match
for word in alice_list:
if word not in dictionary_list:
print(word)
Your function split_line() returns a list. You then take the output of the function and append it to the dictionary list, which means each entry in the dictionary is a list of words rather than a single word. The quick fix it to use extend instead of append.
dictionary_list.extend(split_line(line))
A set might be a better choice than a list here, then you wouldn't need the binary search.
--EDIT--
To print words not in the list, just filter the list based on whether your function returns False. Something like:
notfound = [word for word in alice_list if not searching(word, dictionary_list)]
Are you required to use binary search for this program? Python has this handy operator called "in". Given an element as the first operand and and a list/set/dictionary/tuple as the second, it returns True if that element is in the structure, and false if it is not.
Examples:
1 in [1, 2, 3, 4] -> True
"APPLE" in ["HELLO", "WORLD"] -> False
So, for your case, most of the script can be simplified to:
for word in alice_list:
if word not in dictionary_list:
print(word)
This will print each word that is not in the dictionary list.

Finding the next element value of a particular index in a Python list

I have a simple python program to find whether a sentence is a question or not.
from nltk.tokenize import word_tokenize
from nltk.stem.wordnet import WordNetLemmatizer
a = ["what are you doing","are you mad?","how sad"]
question =["what","why","how","are","am","should","do","can","have","could","when","whose","shall","is","would","may","whoever","does"];
word_list =["i","me","he","she","you","it","that","this","many","someone","everybody","her","they","them","his","we","am","is","are","was","were","should","did","would","does","do"];
def f(paragraph):
sentences = paragraph.split(".")
result = []
for i in range(len(sentences)):
token = word_tokenize(sentences[i])
change_tense = [WordNetLemmatizer().lemmatize(word, 'v') for word in token]
input_sentences = [item.lower() for item in change_tense]
if input_sentences[-1]=='?':
result.append("question")
elif input_sentences[0] in question:
find_question = [input_sentences.index(qestion) for qestion in input_sentences if qestion in question]
if len(find_question) > 0:
for a in find_question:
if input_sentences[a + 1] in word_list:
result.append("question")
else:
result.append("not a question")
else:
result.append("not a quetion")
return result
my_result = [f(paragraph) for paragraph in a]
print my_result
But it makes following error.
if input_sentences[a + 1] in word_list:
IndexError: list index out of range
I think problem cause in finding the next element value of the a. Can any one help me to solve this issue.
The problem is that input_sentences.index(qestion) can return the last index of input_sentences, which means that a + 1 will be one larger than there are elements in input_sentences, this then causes the IndexError as you are trying to access an element of the list in if input_sentences[a + 1] in word_list: which does not exist.
You're logic for checking the "next element" therefore is incorrect, the last element in a list does not have a "next element". Looking at your wordlists a question like What should I do will fail as do will be picked up as a question word but there is nothing after it (assuming you strip punctuation). So you need to rethink the way in which you detect a question.

solving algorithm bug when list item appears more than one time in text

This function has to detect the negation words in text and add NEG_ prefix to the word after negation word. the logic is to save the index of negation word in text list, then add the NEG_prefix to (index+1)
The problem is that, when the text has for example more that one "not", it is not working correctly.
def negationDetection(tweet):
position = []
words = tweet.split()
#to prevent error when negation word appears at the end of text
size = len(words)-1
print words
negationList = ["not","no","never"]
for word in words:
if word in negationList:
if words.index(word) != size:
position.append(words.index(word) + 1)
else:
continue
else:
continue
print position
for i in position:
tweet = (tweet).replace(words[i], 'NEG_' + words[i])
return tweet
a = "hello I am not good,but I can never feel it"
print negationDetection(a)
The result is
hello I am not NEG_good,but I can never NEG_feel it
It is correct, but when the text is "hello I am not good,but I can not feel it", the result is
hello I am not NEG_NEG_good,but I can not feel it
instead of
hello I am not NEG_good,but I can not NEG_feel it
How can I fix this bug?
Your bug is in:
position.append(words.index(word) + 1)
You get the position of word, in this case 'not', using index. This always returns the first occurrence of the word. An easier way is to iterate over index rather then iterate over word.
negationList = ["not","no","never"]
for word in range(len(words)):
if words[word] in negationList:
if word != size:
position.append(word + 1)
else:
continue
else:
continue

Categories

Resources