List index out of range in indented for loops - python

I am trying to make a program that searches a list of strings, using a second list. The first list is a list of random jumbled up letters and the second is a list of words. The program is supposed to detect whether a word in the each word in the second list can be found in any of the strings in the first. If it is, then the word that was found is added to an empty, third list.
counter = 0
for a in FirstList:
for b in SecondList:
if SecondList[counter] in FirstList[counter]:
ThirdList += [SecondList[counter]]
counter += 1
if counter >= len(SecondList):
break
return ThirdList
However, it throws up an error on the first if statement claiming that the list index is out of range. I don't quite understand what I am missing, because I am not editing the contents of any of the lists that I am iterating through, which is what the reason for this error was in other posts about the same error.

The issue here is you are you using a counter which should break at the size of SecondList, but if the FirstList is smaller "counter" will be out of bounds for the FirstList.
I think this may be closer to what you are trying to achieve:
ThirdList = [word for word in SecondList for string in FirstList if word in string]
This is a list comprehension which is running through both lists and outputting any values from the second list which appear in any of the values in the first list.
So for example with the code:
FirstList = ["aadada", "asdtest", "hasdk"]
SecondList = ["test", "data"]
ThirdList = [word for word in SecondList for string in FirstList if word in string]
print(ThirdList)
You would receive the output: "test" as test is found in the FirstList.

You should not iterate over the two lists. Your counter is exceding the amount of elements in both lists. If I understand well what you are trying to do, you could use the following code:
ThirdList = []
for word in SecondList:
for random_word in FirstList:
if word in random_word and word not in ThirdList:
ThirdList.append(word)
return ThirdList
You can remove the second condition of the if statement if you have no problem with duplicate elements in ThirdList.

Related

Python code to compute anagrams without reptetitions

I am solving a python exercise that asks me to find all the possible anagrams of a word but excluding the anagrams that occur more then once.
Here is the code I have come up with:
from itertools import permutations
seq = getString('Insert ')
seq = permutations(seq) # this let us get all anagrams WITH repetitions
unique = []
unique2=[]
for x in seq:
unique.append(x)
i=0
while i < len(unique):
if unique[i] in unique[i+1:]:
i=i+1
continue
if unique[i] not in unique[i+1:]:
unique2.append(unique[i])
i=i+1
What the while does is basically this: consider the ith-anagram and check if in the next part of the list there is an anagram that is identical to the one we are checking. If yes, increase the counter "i" and go on, otherwise append that anagram (that we are sure it does not have repetitions) to another new list.
This goes on up until we reach an i that has a lenght equal to the lenght of the list of permutations with repetitions.

Reverse words cant seem to find them all

One thing I am trying to do is find words that are reversed and are greater or equal to 5 characters, for the following code I have it finds palindrome and any word that is the same backwards
However, I cannot figure out how to get it find 'Damon' or 'nomad'
I have tried using sorted() to get anagrams but unable to implement it.
import sys
word = []
backword = []
def main():
for lines in sys.stdin:
word.append(lines.strip())
for element in word:
if len(element.lower()) >= 5 and element.lower() == element[::-1].lower():
backword.append(element)
print(backword)
if __name__ == '__main__':
main()
Edit - Thank you for your solutions I have to find another way that does it fast...
If I understand correctly then you're looking for any word in a list that is the reverse of another word in the list? In that case you have a few options.
Case 1: You can precompute the list of reversed characters like so:
reversed = [element[::-1].lower() for element in word if len(element) >= 5]
backword = [element for element in word if element.lower() in reversed]
Making a map may also be faster:
reversed = map(lambda s: s.lower()[::-1], word)
backword = [element for element in word if element.lower() in reversed]
Case 2: You can reverse and check each time like so:
backword = [element for element in word if element[::-1] in word]
In the case that you have capitalized words that you haven't filtered out:
backword = [element for element in word if element[::-1] in word or element[::-1].lower().capitalize() in word]
In the case where you have mixed casing in word you should go with case 1 as you can precompute both values with reduced complexity due to the conditions in place.
Using the structure you have provided, this would work:
words = ['Damon', 'test', 'word', 'nomad']
reverse = []
words_set = set(map(str.lower, words))
for element in words:
if len(element.lower()) >= 5 and element.lower()[::-1] in words_set:
reverse.append(element)
print(reverse)
# ['Damon', 'nomad']

Intro to Python - Lists questions

we've started doing Lists in our class and I'm a bit confused thus coming here since previous questions/answers have helped me in the past.
The first question was to sum up all negative numbers in a list, I think I got it right but just want to double check.
import random
def sumNegative(lst):
sum = 0
for e in lst:
if e < 0:
sum = sum + e
return sum
lst = []
for i in range(100):
lst.append(random.randrange(-1000, 1000))
print(sumNegative(lst))
For the 2nd question, I'm a bit stuck on how to write it. The question was:
Count how many words occur in a list up to and including the first occurrence of the word “sap”. I'm assuming it's a random list but wasn't given much info so just going off that.
I know the ending would be similar but no idea how the initial part would be since it's string opposed to numbers.
I wrote a code for a in-class problem which was to count how many odd numbers are on a list(It was random list here, so assuming it's random for that question as well) and got:
import random
def countOdd(lst):
odd = 0
for e in lst:
if e % 2 = 0:
odd = odd + 1
return odd
lst = []
for i in range(100):
lst.append(random.randint(0, 1000))
print(countOdd(lst))
How exactly would I change this to fit the criteria for the 2nd question? I'm just confused on that part. Thanks.
The code to sum -ve numbers looks fine! I might suggest testing it on a list that you can manually check, such as:
print(sumNegative([1, -1, -2]))
The same logic would apply to your random list.
A note about your countOdd function, it appears that you are missing an = (== checks for equality, = is for assignment) and the code seems to count even numbers, not odd. The code should be:
def countOdd(lst):
odd = 0
for e in lst:
if e%2 == 1: # Odd%2 == 1
odd = odd + 1
return odd
As for your second question, you can use a very similar function:
def countWordsBeforeSap(inputList):
numWords = 0
for word in inputList:
if word.lower() != "sap":
numWords = numWords + 1
else:
return numWords
inputList = ["trees", "produce", "sap"]
print(countWordsBeforeSap(inputList))
To explain the above, the countWordsBeforeSap function:
Starts iterating through the words.
If the word is anything other than "sap" it increments the counter and continues
If the word IS "sap" then it returns early from the function
The function could be more general by passing in the word that you wanted to check for:
def countWordsBefore(inputList, wordToCheckFor):
numWords = 0
for word in inputList:
if word.lower() != wordToCheckFor:
numWords = numWords + 1
else:
return numWords
inputList = ["trees", "produce", "sap"]
print(countWordsBeforeSap(inputList, "sap"))
If the words that you are checking come from a single string then you would initially need to split the string into individual words like so:
inputString = "Trees produce sap"
inputList = inputString.split(" ")
Which splits the initial string into words that are separated by spaces.
Hope this helps!
Tom
def count_words(lst, end="sap"):
"""Note that I added an extra input parameter.
This input parameter has a default value of "sap" which is the actual question.
However you can change this input parameter to any other word if you want to by
just doing "count_words(lst, "another_word".
"""
words = []
# First we need to loop through each item in the list.
for item in lst:
# We append the item to our "words" list first thing in this loop,
# as this will make sure we will count up to and INCLUDING.
words.append(item)
# Now check if we have reached the 'end' word.
if item == end:
# Break out of the loop prematurely, as we have reached the end.
break
# Our 'words' list now has all the words up to and including the 'end' variable.
# 'len' will return how many items there are in the list.
return len(words)
lst = ["something", "another", "woo", "sap", "this_wont_be_counted"]
print(count_words(lst))
Hope this helps you understand lists better!
You can make effective use of list/generator comprehensions. Below are fast and memory efficient.
1. Sum of negatives:
print(sum( i<0 for i in lst))
2. Count of words before sap: Like you sample list, it assumes no numbers are there in list.
print(lst.index('sap'))
If it's a random list. Filter strings. Find Index for sap
l = ['a','b',1,2,'sap',3,'d']
l = filter(lambda x: type(x)==str, l)
print(l.index('sap'))
3. Count of odd numbers:
print(sum(i%2 != 0 for i in lst))

While loops list index out of range error. Strip off strings with double slases

I was wondering if could help me debug this code. I'm curious as to why I'm getting a list index out of range error. I'm trying to add up all the items in the list and using the number as the index for the list. In the end, I wanted all strings in the list to cut off '//'.
word_list = []
i = 0
while i < len(word_list):
word_list.extend(['He//llo', 'Ho//w are yo//u', 'Be///gone'])
i += 1
word_list[i].strip('//')
print(i)
print(word_list[i])
print(i)
You condition is never True i < len(word_list), i is 0 and the so is the length of your list so you never enter the loop. You cannot index an empty list so print(word_list[i]) with i being 0 gives you an IndexError.
Your next problem is adding more items to your list in the loop so if you did start the loop it would be infinite as the list size would grow faster than i, for example adding a single string to your list initially:
word_list = ["foo"]
i = 0
# i will never be greater than len(word_list) so loops infinitely
while i < len(word_list): # never enter i is not < len(wordlist)
print(i)
word_list.extend(['He//llo', 'Ho//w are yo//u', 'Be///gone'])
i += 1
word_list[i].strip('//')
print(i)
You add 3 elements to your list, you increase i by 1 so that equal an infinite loop. Not sure what your goal is but using a while does not seem to be what you really want.
If you wanted to use a loop to replace the / and you actually have some strings in your list initially:
word_list = ['He//llo', 'Ho//w are yo//u', 'Be///gone']
for i in range(len(word_list)):
word_list[i] = word_list[i].replace("/","")
print(i)
strings are also immutable so you need to reassign the value, you cannot change a string inplace, the above can also simply become a list comp:
word_list = ['He//llo', 'Ho//w are yo//u', 'Be///gone']
word_list[:] = [s.replace("/","") for s in word_list]
I also used str.replace as strip only removes from the start and end of strings.
Here is what's happening in the code:
word_list = [] # you initialize an empty list with no elements
i = 0
while i < len(word_list): # word_list has no elements, so its length is zero
# so this expression is 'while 0 < 0, *which is false*
# so, we skip the loop entirely
print(word_list[i]) # print the word_list[0], the first element of word_list
# word_list has not changed, so still has zero elements at this point
# error! panic! etc
You start with word_list equal to [] which has length 0, and i equal to 0, thus the while loop is never entered (it's false that 0 < 0). When you try to print(word_list[i]) you get an IndexError because there is no ith (0th) element in word_list -- word_list is empty, so index 0 really is out of range.
What you want is presumably:
word_list = ['He//llo', 'Ho//w are yo//u', 'Be///gone']
i = 0
while i < len(word_list):
word_list[i] = word_list[i].replace('//')
print(i, word_list[i])
i += 1
I say "presumably" because maybe you do want the list to grow infinitely and faster than i (joke -- see #Padraic Cunningham's answer, which I think you should accept as the correct one).
use for loop, there no need to keep track of indexing with for loop
import re
for i, w in enumerate(word_list):
word_list[i] = re.sub(r'/+','',w)
print(word_list)
['Hello', 'How are you', 'Begone']

Thinks counter is a string, not an integer

I'm trying to extract the first few elements of a tab-delimited file using the following:
words = []
name_elements = []
counter = 0
for line in f:
words = line.split()
for element in words:
counter = counter + 1
if words[element].isupper():
name_elements = words[0:counter-1]
print type(counter)
When I run this code, I get this error:
TypeError: list indices must be integers, not str
logout
Even though when I run type(counter) it says it's an integer.
What's the issue?
You are trying to index words with element. element is a string; it is already the item you wanted to get.
The for loop is giving you each element from words in turn, assigning it to the element variable. element is not an integer index into the words list.
Note that your counter is going to go out of bounds; if you want to have an index into the words list along with the element, use the enumerate() function. You are also replacing the name_elements list with a slice from words; perhaps you wanted to extend the list instead:
for line in f:
words = line.split()
for counter, element in enumerate(words):
if element.isupper():
name_elements.extend(words[:counter-1])
although it is not clear exactly what you wanted to do with the words list in this case.

Categories