Python while loop breaking after one iteration - python

inp = (input("Paste in the encoded message (over 100 words):\n")).lower()
inp_list = list(inp)
letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
letter_counter = 26
new_list = []
number_of_es = []
def shift_list(lista):
for item in lista:
if item in letters:
if (letters.index(item) - 1) < 0:
position = (letters.index(item) - 1) + 26
else:
position = (letters.index(item) - 1)
new_list.append(letters[position])
else:
new_list.append(item)
return new_list
while letter_counter > 0:
number_of_es.append(inp_list.count("e"))
print(number_of_es)
letter_counter -= 1
inp_list = shift_list(inp_list)
print(inp_list)
print(letter_counter)
(https://i.stack.imgur.com/fuGrp.png)(https://i.stack.imgur.com/j6oE4.png)
I am a beginner in python but have started trying to write some code that I find interesting. I am trying to make a program that cycles each letter in a line of text through the alphabet, counting the incidences of the letter 'e'.
The problem I am having is that the while loop seems to break after one iteration and I can't see where the problem is.

Python provides two keywords that terminate a loop iteration prematurely:
The Python break statement immediately terminates a loop entirely. Program execution proceeds to the first statement following the loop body.
The Python continue statement immediately terminates the current loop iteration. Execution jumps to the top of the loop, and the controlling expression is re-evaluated to determine whether the loop will execute again or terminate.

Initializing the new_list within the function shift_list() should fix the problem.
Thus a new empty list is created and filled for each function call.
Otherwise the list is always extended because it was a global variable.
inp = (input("Paste in the encoded message (over 100 words):\n")).lower()
inp_list = list(inp)
letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
letter_counter = 26
number_of_es = []
def shift_list(lista):
new_list = []
for item in lista:
if item in letters:
if (letters.index(item) - 1) < 0:
position = (letters.index(item) - 1) + 26
else:
position = (letters.index(item) - 1)
new_list.append(letters[position])
else:
new_list.append(item)
return new_list
while letter_counter > 0:
number_of_es.append(inp_list.count("e"))
print(number_of_es)
letter_counter -= 1
inp_list = shift_list(inp_list)
print(inp_list)
print(letter_counter)

Related

Once the end of a list is reached go back to the beginning, python

I have the list "alphabet" that has all the letters, and the program should with a certain word generate a sequence of letters using an number that gives the user, eg:
Word input = "sun"
Shift_number input = 3
alphabet = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
The output should be "vxq" because the index moved three spaces to the right, my problem is when the moves of the index exceeds the number of variables in the list, eg:
Word input = "zero"
Shift_number = 1
The output should be "afsp" but instead I get this error: "list index out of range". I just need that the index goes to "z" to "a"
Take modulus to stay within the array bounds (index % 26, returning a range between 0-25 in the alphabet array of size 26):
>>> "".join([alphabet[(alphabet.index(i) + 3) % 26] for i in "sun"])
'vxq'
>>> "".join([alphabet[(alphabet.index(i) + 1) % 26] for i in "zero"])
'afsp'
(alphabet.index(i) + N) % 26 will increment the index by N cyclically in your array.
Use itertools.cycle and string.ascii_lowercase:
from itertools import cycle
import string
circular_alphabet = cycle(string.ascii_lowercase)
"".join(next(circular_alphabet ) for _ in range(50))
'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwx'

Remove words from list containing certain characters

I have a long list of words that I'm trying to go through and if the word contains a specific character remove it. However, the solution I thought would work doesn't and doesn't remove any words
l3 = ['b', 'd', 'e', 'f', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y']
firstcheck = ['poach', 'omnificent', 'aminoxylol', 'teetotaller', 'kyathos', 'toxaemic', 'herohead', 'desole', 'nincompoophood', 'dinamode']
validwords = []
for i in l3:
for x in firstchect:
if i not in x:
validwords.append(x)
continue
else:
break
If a word from firstcheck has a character from l3 I want it removed or not added to this other list. I tried it both ways. Can anyone offer insight on what could be going wrong? I'm pretty sure I could use some list comprehension but I'm not very good at that.
The accepted answer makes use of np.sum which means importing a huge numerical library to perform a simple task that the Python kernel can easily do by itself:
validwords = [w for w in firstcheck if all(c not in w for c in l3)]
you can use a list comprehension:
import numpy as np
[w for w in firstcheck if np.sum([c in w for c in l3])==0]
It seems all the words contain at least 1 char from l3 and the output of above is an empty list.
If firstcheck is defined as below:
firstcheck = ['a', 'z', 'poach', 'omnificent']
The code should output:
['a', 'z']
If you want to avoid all loops etc, you can use re directly.
import re
l3 = ['b', 'd', 'e', 'f', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y']
firstcheck = ['azz', 'poach', 'omnificent', 'aminoxylol', 'teetotaller', 'kyathos', 'toxaemic', 'herohead', 'desole', 'nincompoophood', 'dinamode']
# Create a regex string to remove.
strings_to_remove = "[{}]".format("".join(l3))
validwords = [x for x in firstcheck if re.sub(strings_to_remove, '', x) == x]
print(validwords)
Output:
['azz']
Ah, there was some mistake in code, rest was fine:
l3 = ['b', 'd', 'e', 'f', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y']
firstcheck = ['aza', 'ca', 'poach', 'omnificent', 'aminoxylol', 'teetotaller', 'kyathos', 'toxaemic', 'herohead', 'desole', 'nincompoophood', 'dinamode']
validwords = []
flag=1
for x in firstcheck:
for i in l3:
if i not in x:
flag=1
else:
flag=0
break
if(flag==1):
validwords.append(x)
print(validwords)
So, here the first mistake was, the for loops, we need to iterate through words first then, through l3, to avoid the readdition of elements.
Next, firstcheck spelling was wrong in 'for x in firstcheck` due to which error was there.
Also, I added a flag, such that if flag value is 1 it will add the element in validwords.
To, check I added new elements as 'aza' and 'ca', due to which, now it shows correct o/p as 'aza' and 'ca'.
Hope this helps you.

find words in a list of lists

I need to find words in a list of lists (a somewhat matrix), by entering a given direction to search.
so for example, if I need to search all words that are horizontal from right to left - I will do that by manipulating the indexes that run over the columns.
the_matrix = [['a', 'p', 'p', 'l', 'e'],
['a', 'g', 'o', 'd', 'o'],
['n', 'n', 'e', 'r', 't'],
['g', 'a', 'T', 'A', 'C'],
['m', 'i', 'c', 's', 'r'],
['P', 'o', 'P', 'o', 'P']]
the_word_list = ['ert','PoP']
def find_words_in_matrix(directions):
good_list = []
for col in range(len(the_matrix[0])):
for row in range(len(the_matrix)):
for word in the_word_list:
for i in range(len(word)):
found_word = True
#a = word[i]
if col + i > len(the_matrix[0])-1:
break
#b = the_matrix[row][col+i]
if word[i] != the_matrix[row][col+i]:
found_word=False
break
if found_word is True:
good_list.append(word)
return good_list
Im getting the output:
['PoP', 'ert', 'PoP', 'ert', 'PoP']
instead of:
['PoP', 'ert', 'PoP']
*pop shows up twich at the bottom line, not three times. and ert only once.
that is my problem
thanks for the help!
You are getting stray matches when the break terminates the loop early before the whole word has matched. To eliminate this, you can keep track of the match length:
def find_words_in_matrix(directions):
good_list = []
for col in range(len(the_matrix[0])):
for row in range(len(the_matrix)):
for word in the_word_list:
match_len = 0
for i in range(len(word)):
found_word = True
#a = word[i]
if col + i > len(the_matrix[0])-1:
break
#b = the_matrix[row][col+i]
if word[i] != the_matrix[row][col+i]:
found_word=False
break
match_len += 1
if (match_len == len(word)) and (found_word is True):
good_list.append(word)
return good_list

How to check if one string's characters exist and are in the same position as those in another string?

I have a list containing the characters of this string:
wordtoguess = ['T', 'R', 'A', 'N', 'S', 'M', 'I', 'S', 'S', 'I', 'O', 'N']
And I have the user guess a word and store it in the variable 'guessed'. I also have a variable called 'correct_chars' which is equal to 0.
guessed = input()
correct_chars = 0
When the user guesses a word I want Python to iterate through each character of the word and if it exists and is in the same place as the corresponding character in wordtoguess, to add 1 to correct_chars. For example if the user inputted the string 'translations', then correct_chars would be equal to 5. I have been unable to figure out how to do this so far.
Here's a potential implementation:
>>> wordtoguess = "TRANSMISSION"
>>> guessed = "TRANSLATIONS"
>>> correct_chars = sum(1 for (x, y) in zip(wordtoguess, guessed) if x.lower() == y.lower())
>>> correct_chars
5
guessed = input()
correct_chars = 0
wordtoguess = ['T', 'R', 'A', 'N', 'S', 'M', 'I', 'S', 'S', 'I', 'O', 'N']
for i, c in enumerate(guessed):
try:
if c.upper() == wordtoguess[i]:
correct_chars += 1
except IndexError:
pass
print(correct_chars)
Here's a possible solution
guessed = input()
correct_chars = 0
wordtoguess = ['T', 'R', 'A', 'N', 'S', 'M', 'I', 'S', 'S', 'I', 'O', 'N']
for i in range( len(wordtoguess) ):
if i >= len(guessed):
break
if wordtoguess[i] == guessed[i]:
correct_chars = 0

My python method isn't working correctly, skipping items in a list (playfair cipher)

I'm trying to write a method that takes a key and an alphabet and creates a playfair cipher box. For those of you that don't know what that is, It takes the key and puts it in a 5 x 5 grid of letters, spilling onto the next line if neccessary, and then adds the rest of the letters of the alphabet. Each letter is only supposed to appear in the box once. I'm trying to do this with a list with 5 internal lists, each with 5 items. the only problem is that where the method is supposed to skip letters, it isn't. Here is the method and the output, can anyone help me?
def makePlayFair(key, alpha):
box = []
#join the key and alphabet string so that you only have to itterate over one string
keyAlpha = ""
keyAlpha = keyAlpha.join([key, alpha])
ind = 0
for lines in range(5):
line = []
while len(line) < 5:
if isIn(keyAlpha[ind], box) or isIn(keyAlpha[ind], line):
print(isIn(keyAlpha[ind],box))
ind += 1
continue
else:
line.append(keyAlpha[ind])
ind += 1
box.append(line)
return box
def isIn(item, block):
there = None
for each_item in block:
if type(each_item) == type([]):
for nested_item in each_item:
if item == nested_item:
there = True
break
else:
there = False
else:
if item == each_item:
there = True
break
else:
there = False
return there
>>> makePlayFair("hello", alphabet) #alphabet is a string with all the letters in it
> `[['h', 'e', 'l', 'o', 'a'], ['b', 'c', 'd', 'f', 'g'], ['h', 'i', 'j', 'k', 'l'], ['m', 'n', 'o', 'p', 'q'], ['r', 's', 't', 'u', 'v']]`
Thanks for your help in advance!
cheers, brad
Your problem is in isIn:
Your break statement only breaks out of the inner for loop. The code then continues to iterate over the second for loop. This means that only the last one is considered. You have to make sure that you exit out of both loops for this to work correctly.
The entire process can be made simpler by doing something like:
def makePlayFair(key, alpha):
letters = []
for letter in key + alpha:
if letter not in letters:
letters.append(letter)
box = []
for line_number in range(5):
box.append( letters[line_number * 5: (line_number+1) * 5])
Make the list of letters first, then break them up into the 5x5 grid:
def takeNatATime(n, seq):
its = [iter(seq)]*n
return zip(*its)
def makePlayfair(s):
keystr = []
for c in s + "abcdefghijklmnopqrstuvwxyz":
if c not in keystr:
keystr.append(c)
return list(takeNatATime(5, keystr))
print makePlayfair("hello")
Prints:
[('h', 'e', 'l', 'o', 'a'), ('b', 'c', 'd', 'f', 'g'), ('i', 'j', 'k', 'm', 'n'), ('p', 'q', 'r', 's', 't'), ('u', 'v', 'w', 'x', 'y')]
Here's my attempt:
#!/usr/bin/env python
from string import ascii_uppercase
import re
def boxify(key):
cipher = []
key = re.sub('[^A-Z]', '', key.upper())[:25]
for i in range(max(25 - len(key), 0)):
for letter in ascii_uppercase:
if letter not in key:
key += letter
break
for i in range(0, 25, 5):
cipher.append(list(key[i:i+5]))
return cipher
if __name__ == "__main__":
print boxify("This is more than twenty-five letters, i'm afraid.")
print boxify("But this isn't!")

Categories