Python how to access list item with a variable - python

I searched for this for a while tonight, but I didn't find anything... or maybe I'm too noob to understand?
Well here's my code, the question will follow, I think that you'll understand it better if I show you the code now:
lencount = 1
decrypted = []
while lencount <= length:
if intlist[lencount] == 2:
print('OK!')
decrypted.append(alphabet[2])
lencount += 1
print(decrypted)
Here's the whole code, if you want to see:
import os
# os.system("multimon-ng -a dtmf -q | grep -x -E '[0-9]+' --line-buffered >> $HOME/dtmf.txt")
file=open('/home/nicolasmailloux/dtmf.txt')
line=file.read()
text = line.replace("\n", "")
n = 2
chars = [c for c in text]
ngrams = []
for i in range(len(chars)-n + 1):
ngram = "".join(chars[i:i+n])
ngrams.append(ngram)
intlist = list(map(int, ngrams))
length = int(len(intlist))
print(length)
print(intlist)
# Defining some variables
alphabet = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
lencount = 1
decrypted = []
while lencount <= length:
if intlist[lencount] == 2:
print('OK!')
decrypted.append(alphabet[2])
lencount += 1
print(decrypted)
The thing is that the amount of items in the lists is variable and I can't access it (why??) by using a variable in intlist[lencount]. This is confusing. Here's the output I have when I try to run the program:
if intlist[lencount] == 2:
IndexError: list index out of range
Thanks for helping!

This occurs because the len() function returns:
The length (the number of items) of an object.
However, lists are zero-indexed in Python, meaning that some_list[len(some_list)] will always be out of range, because len() does not take zero-indexing into account.
Because of this, the conditional while lencount <= length allows intlist[len(intlist)] to occur, which by definition is out of range. This can be solved with the following:
while lencount < length:
if intlist[lencount] == 2:
print('OK!')
...
Additionally, assuming you want to go through all values of intlist, lencount should be initialized to 0, so:
lencount = 0

Here's the problem:
length = int(len(intlist))
in combination with
while lencount <= length:
if intlist[lencount] == 2:
lencount=length is out of range (indices go from 0, ..., len(list)-1).

lencount = 1
problem is your lencount starting with 1
your while loop is something like that,
lencount = 30
if intlist[31] == 2:
but inlist len is 30,
you are trying to find index 31

Related

Python while loop breaking after one iteration

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)

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'

What's the most effective way to Iterate, while manipulating a list or string?

My goal is to create a code breaker in python. So far I have jumbled up the letters and as a result have a list of individual characters.
#Result of inputting the string 'hello world'
['C', 'V', 'N', 'N', 'H', 'X', 'H', 'K', 'N', 'O']
My aim is output this as a string with a space 'CVNNH XHKNO'
Now I have several options but I'm unsure which one would the best:
Do I convert it to a string first before manipulating it or manipulate the list before converting to a string.
I have the following helpers available from the process so far (automatically)
length = [5,5] #list
total_chars = 10 #int
no_of_words = 2 #int
I have converted it to a string CVNNHXHKNO and thought about inserting the space after the 5th letter by calculating a start point[0], mid point[5] and end point[11].
start = 0
mid_point = total_chars - length[0]
print(mid_point)
first_word = message[start:mid_point]
print(first_word)
second_word = message[mid_point:total_chars]
print(second_word)
completed_word = first_word + ' ' + second_word
print(completed_word)
Unfortunately this is just manually and doesn't take into account if there a 5 or more words. I have attempted to iterate over the original list of individual characters in nested for loops using the list length but seem to confuse myself and overthink.
If you have this as inputs:
l = ['C', 'V', 'N', 'N', 'H', 'X', 'H', 'K', 'N', 'O']
length = [5,5] #list
total_chars = 10 #int
no_of_words = 2 #int
Then you can compute your output as follow:
words = []
pos = 0
for i in length:
words.append("".join(l[pos:pos+i]))
pos += i
result = " ".join(words)
print(words)
print(result)
Output:
['CVNNH', 'XHKNO']
CVNNH XHKNO
I do not fully understand your question, but probably what you want is something like
letters = ['C', 'V', 'N', 'N', 'H', 'X', 'H', 'K', 'N', 'O']
length = [5, 5]
words = []
offset = 0
for i in length:
words.append(''.join(letters[offset:offset+i]))
offset += i
string_words = ' '.join(words)
print(string_words)
lst = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
WORD_SIZE = 5
NUM_WORDS = 2 # You could replace this with `len(lst) / WORD_SIZE`
result = ' '.join(
''.join(
lst[i * WORD_SIZE: i * WORD_SIZE + 5]
)
for i in range(NUM_WORDS)
)
# result = 'abcde fghij'
To be able to use infinitely long lists of lengths as input, you could iterate over the length list and join the corresponding letters:
letters = ["A", "S", "I", "M", "P", "L", "E", "T", "E", "S", "T"]
length = [1, 6, 4]
starting_index = 0
for l in length:
print("".join(letters[starting_index:starting_index+l]))
starting_index += l
It looks like you just need your length list describing how many letters in each word:
message = ['C', 'V', 'N', 'N', 'H', 'X', 'H', 'K', 'N', 'O']
length = [5,5]
offset = 0
words = []
for size in length:
words.append(''.join(message[offset:offset+size]))
offset += size
completed_word = ' '.join(words)
print(completed_word)
Output:
CVNNH XHKNO

Iterate through letters of an unknown length of digits

Okay... I need to iterate through strings with arbitrary lengths. Since I don't know how to explain this too well, I mean like this:
def zip(string1,string1):
...
and when called with "a" and "ad" it would return a list:
>>>zip("a","ad")
["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","aa","ab","ac","ad"]
I've tried using map(chr,range(ord('a'),ord('nb')+1)) but I get TypeError: ord() expected a character, but string of length 2 found, and I don't know where to go from here. Any ideas?
That's it:
def zip_(start, end):
def __inc(s):
if not s:
return "a"
elif s[-1] != "z":
return s[:-1] + chr(ord(s[-1]) + 1)
else:
return __inc(s[:-1]) + "a"
s = start
yield s
while s != end:
s = __inc(s)
yield s
print list(zip_("a", "ad"))
A few comments:
Don't use the word zip as a name of a variable or a function, because it's already reserved.
In the solution zip_ is a generator. I did it in order to not keep too much data in memory. If you need an exact list, just convert it as I've done in the print-statement.
In case of wrong arguments the function may go into an infinite loop. For example, if you call zip_("b", "a"). But actually it's easy to fix by adding a few lines if it's necessary.
This is a base-26 number system and here is how I would solve it. And also zip is a python built-in function, probably better not to redefine it.
def alphaToNumber(s):
r = 0
for x in s:
r *= 26
r += ord(x) - 96
return r
def numberToAlpha(n, result):
head = (n - 1) // 26
tail = chr((n - 1) % 26 + 97)
if head == 0:
return tail + result
else:
return numberToAlpha(head, tail + result)
def gen(start, end):
start_n = alphaToNumber(start)
end_n = alphaToNumber(end)
return [numberToAlpha(x, "") for x in range(start_n, end_n + 1)]
print(gen("a", "ad"))
# ['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', 'aa', 'ab', 'ac', 'ad']

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