for loop exit if condition is not met - python

I am trying to write a Shiritori game in Python. In the game you are given a word (ex: dog) and you must to add another word that starts with the end of the previous word ex(: doG, Goose).
So given a list words = ['dog', 'goose', "elephant" 'tiger', 'rhino', 'orc', 'cat'] it must return all value, but if "elephant" is missing it must return:
["dog","goose"] because "dog" and "goose" match, but "goose" and "tiger" not.
I am running into a bug where it either loop out of range checking next index in list or it returns only "dog" and not "goose", or it returns ["dog","goose"] and than exit the loop without iterating through the rest of the list(s).
What am I doing wrong?
def(game():
words = ['dog', 'goose', 'tiger', 'rhino', 'orc', 'cat']
check_words = ['goose', 'tiger', 'rhino', 'orc', 'cat']
# check words has one less element to avoid index out or range in the for loop
# example = if word[-1] != words[index+1][0]: # index+1 gives error
good_words = []
for index, word in enumerate(words):
for index2, word2 in enumerate(check_words):
# I want to add the correct pair and keep looping if True
if word[-1] == word2[0]:
good_words.extend([word,word2])
return good_words # break out of the loop ONLY when this condition is not met
print(game())

your code need an indent after "def game():".

I am not sure why you needed the 2nd for loop.
here is a solution.
def game():
words = ['dog', 'goose', 'elephant', 'utiger', 'rhino', 'orc', 'cat']
good_words = []
for index in range(0, len(words)):
if index+1 < len(words):
previous_word = words[index][-1]
next_word = words[index+1][0]
if previous_word == next_word:
# appends the new word if not in list
if words[index] in good_words:
good_words.append(words[index+1])
else:
# only used for the first time to append the current and the next word
good_words.append(words[index])
good_words.append(words[index+1])
else:
return good_words # break out of the loop ONLY when this condition is not met
return good_words
print(game())

Related

How to find words in a list that contain the same first letter python

Write a function common_start(word_list) that takes in parameter a list of words.
This function must return a new list containing all words that start with the same letter as at least one other word in the list.
input: ['file', 'edit', 'view', 'insert', 'format']
output: ['file', 'format']
A one line solution, if you want
def common_start(input_list):
return [word for word in input_list if sum([w.startswith(word[0]) for w in input_list]) > 1]
This should work for you.
In this case I'm ignoring the duplicated words.
def common_start(word_list):
output = set()
for word in word_list:
for first_letter in word_list:
if word == first_letter:
next
elif word[0] == first_letter[0]:
output.add(word)
return list(output)
Input: ['tara', 'file', 'edit', 'view', 'insert', 'format','test']
Output: ['tara', 'file', 'format', 'test']

Iterating through list and using remove() doesn't produce desired result

I’m a programming neophyte and would like some assistance in understanding why the following algorithm is behaving in a particular manner.
My objective is for the function to read in a text file containing words (can be capitalized), strip the whitespace, split the items into separate lines, convert all capital first characters to lowercase, remove all single characters (e.g., “a”, “b”, “c”, etc.), and add the resulting words to a list. All words are to be a separate item in the list for further processing.
Input file:
A text file (‘sample.txt’) contains the following data - “a apple b Banana c cherry”
Desired output:
[‘apple’, ‘banana’, ‘cherry’]
In my initial attempt I tried to iterate through the list of words to test if their length was equal to 1. If so, the word was to be removed from the list, with the other words remaining in the list. This resulted in the following, non-desired output: [None, None, None]
filename = ‘sample.txt’
with open(filename) as input_file:
word_list = input_file.read().strip().split(' ')
word_list = [word.lower() for word in word_list]
word_list = [word_list.remove(word) for word in word_list if len(word) == 1]
print(word_list)
Produced non-desired output = [None, None, None]
My next attempt was to instead iterate through the list for words to test if their length was greater than 1. If so, the word was to be added to the list (leaving the single characters behind). The desired output was achieved using this method.
filename = ‘sample.txt’
with open(filename) as input_file:
word_list = input_file.read().strip().split(' ')
word_list = [word.lower() for word in word_list]
word_list = [word for word in word_list if len(word) > 1]
print(word_list)
Produced desired Output = [‘apple’, ‘banana’, ‘cherry’]
My questions are:
Why didn’t the initial code produce the desired result when it seemed to be the most logical and most efficient?
What is the best ‘Pythonic’ way to achieve the desired result?
The reason you got the output you got is
You're removing items from the list as you're looping through it
You are trying to use the output of list.remove (which just modifies the list and returns None)
Your last list comprehension (word_list = [word_list.remove(word) for word in word_list if len(word) == 1]) is essentially equivalent to this:
new_word_list = []
for word in word_list:
if len(word) == 1:
new_word_list.append(word_list.remove(word))
word_list = new_word_list
And as you loop through it this happens:
# word_list == ['a', 'apple', 'b', 'banana', 'c', 'cherry']
# new_word_list == []
word = word_list[0] # word == 'a'
new_word_list.append(word_list.remove(word))
# word_list == ['apple', 'b', 'banana', 'c', 'cherry']
# new_word_list == [None]
word = word_list[1] # word == 'b'
new_word_list.append(word_list.remove(word))
# word_list == ['apple', 'banana', 'c', 'cherry']
# new_word_list == [None, None]
word = word_list[2] # word == 'c'
new_word_list.append(word_list.remove(word))
# word_list == ['apple', 'banana', 'cherry']
# new_word_list == [None, None, None]
word_list = new_word_list
# word_list == [None, None, None]
The best 'Pythonic' way to do this (in my opinion) would be:
with open('sample.txt') as input_file:
file_content = input_file.read()
word_list = []
for word in file_content.strip().split(' '):
if len(word) == 1:
continue
word_list.append(word.lower())
print(word_list)
In your first approach, you are storing the result of word_list.remove(word) in the list which is None. Bcz list.remove() method return nothing but performing action on a given list.
Your second approach is the pythonic way to achieve your goal.
The second attempt is the most pythonic. The first one can still be achieved with the following:
filename = 'sample.txt'
with open(filename) as input_file:
word_list = input_file.read().strip().split(' ')
word_list = [word.lower() for word in word_list]
for word in word_list:
if len(word) == 1:
word_list.remove(word)
print(word_list)
Why didn’t the initial code produce the desired result when it seemed
to be the most logical and most efficient?
It's advised to never alter a list while iterating over it. This is because it is iterating over a view of the initial list and that view will differ from the original.
What is the best ‘Pythonic’ way to achieve the desired result?
Your second attempt. But I'd use a better naming convention and your comprehensions can be combined as you're only making them lowercase in the first one:
word_list = input_file.read().strip().split(' ')
filtered_word_list = [word.lower() for word in word_list if len(word) > 1]

How to make index read entire list?

I'm working on a project for my Python course and I'm still pretty new to coding in general. I'm having issues with one of the snippets of my code. I'm trying to make Python find every instance of the word "the" (or any input word really, it doesn't matter.) and return the word immediately after it. I am able to make it return the word after "the", but it stops after one instance when I need it to scan the entire list.
Here is my code:
the_list=['the']
animal_list=['the', 'cat', 'the', 'dog', 'the', 'axolotl']
for the_list in animal_list:
nextword=animal_list[animal_list.index("the")+1]
continue
print(nextword)
All I'm returning is cat whereas dog and axolotl should pop up as well. I tried using a for loop and a continue in order to make the code go through the same process for dog and axolotl, but it didn't work.
I am not clear what you are asking for, but I think what you want is to get the animals that are in the list animal_list, and assuming that the word 'the' is in the even indeces, you can use this;
animals = [animal for animal in animal_list if animal != 'the']
Since you are a beginner, the previous code uses a comprehension which is a pythonic way to iterate over a loop without a for loop, the equivalent code to the previous one using a for loop is:
animals = []
for animal in animal_list:
if animal != 'the':
animals.append(animal)
index only will get the first instance.
The typical pythonic way is to use a list comprehension:
[animal_list[i+1] for i,val in enumerate(animal_list) if val=='the']
list.index will only find the first occurrence, however you can specify a start and stop value to skip over other indexes.
Now we also need to use a try/except block because list.index will raise a ValueError in the case that it doesn't find a match.
animal_list=['the', 'cat', 'the', 'dog', 'the', 'axolotl']
match = 'the'
i = 0
while True:
try:
i = animal_list.index(match, i) + 1 # start search at index i
except ValueError:
break
# can remove this check if certain that your list won't end with 'the'
# otherwise could raise IndexError
if i < len(animal_list):
print(animal_list[i])
However in case you don't have to use list.index, I would suggest the following instead. (Again can remove the check if list won't end with 'the'.
for i, item in enumerate(animal_list):
if item == match and i + 1 < len(animal_list):
print(animal_list[i + 1])
Or more compact is to use list comprehension. Which will output a list of all items after 'the'.
animals = [ animal_list[i + 1] for i, v in enumerate(animal_list)
if v == match and i + 1 < len(animal_list) ]
print(animals)
Note: The use of continue is not correct. continue is used when you want to end the current iteration of the loop and move on to the next. For example
for i in range(5):
print(i)
if i == 2:
continue
print(i)
# Output
0
0
1
1
2 # Notice only '2' is printed once
3
3
4
4
One approach is to zip the list to a shifted version of itself:
keyword = 'the'
animal_list=['the', 'cat', 'the', 'dog', 'the', 'axolotl']
zipped = zip(animal_list, animal_list[1:])
# zipped contains [('the', 'cat'), ('cat', 'the'), ('the', 'dog') etc.]
found_words = [after for before, after in zipped if before == 'the']
This will deal with a list that ends in 'the' without raising an error (the final 'the' will simply be ignored).
the_word = 'the'
animal_list = ['the', 'cat', 'the', 'dog', 'the', 'axolotl']
# Iterate through animal_list by index, so it is easy to get the next element when we find the_word
for i in range(len(animal_list) - 1):
if animal_list[i] == the_word: # if the current word == the word we want to find
print(animal_list[i+1]) # print the next word
We dont want to check the last element in animal_list. That is why I subtract 1 from the length of animal_list. That way i will have values of 0, 1, 2, 3, 4.
Try this:
the_list=['the']
animal_list=['the', 'cat', 'the', 'dog', 'the', 'axolotl']
i=0
for i in range(len(animal_list)):
if animal_list[i] in the_list:
nextword=animal_list[i+1]
print nextword
This is a very UN-PYTHONIC way of doing this...but perhaps it'll help you understand indexes:
animal_list = ['the', 'cat', 'the', 'dog', 'the', 'axolotl']
index=0
for x in animal_list:
if x == "the":
print(animal_list[(index + 1)])
index +=1

How can I simplify my code in an efficient way?

so currently im stuck on a question of my assignment,
the assignment question is:
Define the print_most_frequent() function which is passed two parameters, a dictionary containing words and their corresponding frequencies (how many times they occurred in a string of text), e.g.,
{"fish":9, "parrot":8, "frog":9, "cat":9, "stork":1, "dog":4, "bat":9, "rat":4}
and, an integer, the length of the keywords in the dictionary which are to be considered.
The function prints the keyword length, followed by " letter keywords: ", then prints a sorted list of all the dictionary keywords of the required length, which have the highest frequency, followed by the frequency. For example, the following code:
word_frequencies = {"fish":9, "parrot":8, "frog":9, "cat":9, "stork":1, "dog":4, "bat":9, "rat":4}
print_most_frequent(word_frequencies,3)
print_most_frequent(word_frequencies,4)
print_most_frequent(word_frequencies,5)
print_most_frequent(word_frequencies,6)
print_most_frequent(word_frequencies, 7)
prints the following:
3 letter keywords: ['bat', 'cat'] 9
4 letter keywords: ['fish', 'frog'] 9
5 letter keywords: ['stork'] 1
6 letter keywords: ['parrot'] 8
7 letter keywords: [] 0
I have coded to get the answer above however it is saying I'm wrong. Maybe it needs a simplifying but i'm struggling how to. Could someone help thank you.
def print_most_frequent(words_dict, word_len):
word_list = []
freq_list = []
for word,freq in words_dict.items():
if len(word) == word_len:
word_list += [word]
freq_list += [freq]
new_list1 = []
new_list2 = []
if word_list == [] and freq_list == []:
new_list1 += []
new_list2 += [0]
return print(new_list1, max(new_list2))
else:
maximum_value = max(freq_list)
for i in range(len(freq_list)):
if freq_list[i] == maximum_value:
new_list1 += [word_list[i]]
new_list2 += [freq_list[i]]
new_list1.sort()
return print(new_list1, max(new_list2))
You can use:
def print_most_frequent(words_dict, word_len):
max_freq = 0
words = list()
for word, frequency in words_dict.items():
if len(word) == word_len:
if frequency > max_freq:
max_freq = frequency
words = [word]
elif frequency == max_freq:
words.append(word)
print("{} letter keywords:".format(word_len), sorted(words), max_freq)
It just iterates over the words dictionary, considering only the words whose length is the wanted one and builds the list of the most frequent words, resetting it as soon as a greater frequency is found.
One way you can do is to map the values as keys and vice-versa, this way you can easily get the most frequent words:
a = {"fish":9, "parrot":8, "frog":9, "cat":9, "stork":1, "dog":4, "bat":9, "rat":4}
getfunc = lambda x, dct: [i for i in dct if dct[i] == x]
new_dict = { k : getfunc(k, a) for k in a.values() }
print (new_dict)
output:
{8: ['parrot'], 1: ['stork'], 4: ['rat', 'dog'], 9: ['bat', 'fish', 'frog', 'cat']}
So, now if you want 9 digit words, simply say
b = new_dict[9]
print (b, len(b))
which will give:
['cat', 'fish', 'bat', 'frog'] 4
You get to use the dictionary, instead of calling the function again and over. This is faster as you loop over the frequencies just once, but if you still need a function, can just do a one-liner lambda maybe:
print_most_frequent = lambda freq, x: print (freq[x])
print_most_frequent(new_dict, 9)
print_most_frequent(new_dict, 4)
which gives:
['fish', 'bat', 'frog', 'cat']
['rat', 'dog']

Python: How would i write this 'if' statement for a word of arbitrary length? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Checking if a string's characters are ascending alphabetically and its ascent is evenly spaced python
This is what I currently have:
wordlist = ['fox', 'aced', 'definite', 'ace']
for word in wordlist:
a = len(word)
if (ord(word[a-(a-1)] - ord(word[(a-a)])) == ord(word[a-(a-2)])-ord(word[a-(a-1)]:
print "success", word
else:
print "fail", word
What I'm trying to do is calculate the ASCII values between each of the letters in the word. And check to see if the ord of the letters are increasing by the same value.
so for fox, it would check if the difference between the ord of 2nd and 1st letters are equal to the ord difference of the 3rd and 2nd letters.
However, with my current 'if' statement, only the first 3 letters of a word are compared. How can I rewrite this statement to cover every letter in a word of length greater than 3?
Sorry if I can't present this clearly, thanks for your time.
Note the use of len(set(...)) < 2:
def check(word):
return len(set(ord(a) - ord(b) for a,b in zip(word,word[1:]))) < 2
wordlist = ['fox', 'aced', 'definite', 'ace']
print filter(check, wordlist)
Prints:
['fox', 'ace']
Consider
import operator
def diff(s):
return map(operator.sub, s[1:], s[:-1])
wordlist = ['fox', 'aced', 'definite', 'ace']
print [w for w in wordlist if len(set(diff(map(ord, w)))) == 1]
## ['fox', 'ace']
The latter expression decomposed:
w = 'fox'
print map(ord, w) # [102, 111, 120]
print diff(map(ord, w)) # [9, 9]
print set(diff(map(ord, w))) # set([9])
print len(set(diff(map(ord, w)))) # 1
I believe you are looking to see of the ord difference between every letter in a word is the same.
def check(word):
return all((ord(ele_1) - ord(ele_2)) == (ord(word[0]) - ord(word[1])) for ele_1,ele_2 in zip(word,word[1:]) )
Result:
>>> check('abcde')
True
>>> check('wdjhrd')
False
Applying to your list:
wordlist = ['fox', 'aced', 'definite', 'ace']
new_list = filter(check, wordlist)
Result:
>>> new_list
['fox', 'ace']
Here's my form which I feel is a little more readable and extendable into a list comprehension.
>>> a = 'ace'
>>> all(ord(a[n])-ord(a[n-1]) == (ord(a[1])-ord(a[0])) for n in xrange(len(a)-1,0,-1))
True
and to iterate through the list of words, a list comprehension:
wordlist = ['fox', 'aced', 'definite', 'ace']
[a for a in wordlist if all(ord(a[n])-ord(a[n-1]) == (ord(a[1])-ord(a[0])) for n in xrange(len(a) -1,0,-1))]
Returns:
['fox', 'ace']
Try this:
wordlist = ['fox', 'aced', 'definite', 'ace', 'x']
for word in wordlist:
if len(word) < 2:
print "fail", word
continue
diff = ord(word[1]) - ord(word[0])
if all(ord(word[i+1])-ord(word[i])==diff for i in xrange(1, len(word)-1)):
print "success", word
else:
print "fail", word
Notice that this solution is efficient, as it doesn't generate any intermediate lists or word slices and the processing inside all() is done with iterators, also all() is "short-circuiting": it will terminate on the first False it finds.
Maybe try changing the ord(word[a-(a-2)]) to ord(word[a-(a-len((word)-1))]). I'm not sure if that's your exact code, but it seems to also be some EOF errors.

Categories