How to replace a character in a list of lists - python

I have to replace some of the list of lists by a specific word given by the user,I tried multiple times and kept getting an error and then after fixing the errors I have a code but the code wont print. Even though I typed print just so I could see how the code ran, nothing shows up.
Here is the list of lists:
table = [['*', '*', '*', '*', '*'],
['*', '*', '*', '*', '*'],
['*', '*', '*', '*', '*'],
['*', '*', '*', '*', '*'],
['*', '*', '*', '*', '*']]
and here is the code I tried:
i = 0
def create_table(secret):
secret = input("Enter the secret Word: ")
secret = secret.upper()
secret = secret.replace('J','I')
return secret
for row in range(5):
for col in range(5):
table = [t.replace(table[row][col], secret[i]) for t in table]
i +=1
print(table)
print(create_table(secret))

You have return secret half way through your function. This means that the remainder of the code in that function will not execute. You should move return secret to the end of the function definition.
You also are accepting a parameter to the create_table() function that you then immediately overwrite, you can get rid of this.

table is a mutable list, so just do:
table[row][col] = secret[i]
and remove the return secret or you won't get to the code.
A simple example:
import pprint
table = [['*', '*', '*', '*', '*'],
['*', '*', '*', '*', '*'],
['*', '*', '*', '*', '*'],
['*', '*', '*', '*', '*'],
['*', '*', '*', '*', '*']]
def create_table():
secret = 'ABCDEFGHIJKLMNOPQRSTUVWXY'
for row in range(5):
for col in range(5):
table[row][col] = secret[row*5 + col]
pprint.pprint(table)
create_table()
Output:
[['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']]

You have few problem with your code.
One thing to note is a function stops further execution once it returns something.*
So, In your function create_table, the lines after your return statement are not being executed at all.
Also note that, you either print from within the function or just return some value and print from the main body. You're printing from inside your function and also calling function as argument to print in main body.
Just do return table from your function and print from the main body. That's just the standard practice and right way to do it.
Or you don't even need to do that since you're modifying a global variable from inside your function anyway.
Edit: To modify the variable table from inside your function, add the line,
global table within your function before you try to make any changes in table so that your function knows it's the global variable you're trying to modify and not creating a new local variable with the same name.
*I think there is a way to work around this.Not sure though.

Related

Trying to convert user define function result into list in python

#Password Generator Project
import random
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', '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']
numbers = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
symbols = ['!', '#', '$', '%', '&', '(', ')', '*', '+']
print("Welcome to the PyPassword Generator!")
nr_letters= int(input("How many letters would you like in your password?\n"))
nr_symbols = int(input(f"How many symbols would you like?\n"))
nr_numbers = int(input(f"How many numbers would you like?\n"))
#Eazy Level - Order not randomised:
#e.g. 4 letter, 2 symbol, 2 number = JduE&!91
def my_function():
for i in range(1,nr_letters+1):
variable=random.choice(letters)
print(variable, end='')
for j in range(1,nr_symbols+1):
variable1=random.choice(symbols)
print(variable1, end='')
for k in range(1,nr_numbers+1):
variable2=random.choice(numbers)
print(variable2, end='')
#Hard Level - Order of characters randomised:
#e.g. 4 letter, 2 symbol, 2 number = g^2jk8&P
#my_function()
function_to_list=my_function()
print[(function_to_list)]
shuffle_my_function=random.shuffle(function_to_list)
print(shuffle_my_function)
This is a kind of personal project here my task is to generate a password. On the easy level just print the password sequence wise whereas on the hard level I want my password to be shuffled.
My easy level code is working perfectly but on the hard level, I want to shuffle the result of the easy level for that I thought that if I define a function of the easy part and then somehow convert that function into the list I can easily use shuffle function . so please help me. please try to do give a solution in my way of thinking and then please suggest your way of doing it
This is a common beginner problem. When you print something, it's there on the screen, but only as text. And the program can't see that text. You have to do something to the variables to keep track of them as you go. In this case, you need to append them to a list. Not only that, but you need to return the list to the caller, so that function_to_list = my_function() assigns something other than None to function_to_list:
def my_function():
list_of_characters = []
for i in range(nr_letters):
list_of_characters.append(random.choice(letters))
for j in range(nr_symbols):
list_of_characters.append(random.choice(symbols))
for k in range(nr_numbers):
list_of_characters.append(random.choice(numbers))
return list_of_characters
Notice that I took out the print statements. That's because a function should do only one thing and do it well. You can print your list and your password as soon as you get them back:
list_from_function = my_function()
print(list_from_function)
To print the list as a single string, join the letters it contains with the emtpy string:
print(''.join(list_from_function))
You can shuffle the result, or do whatever you want:
random.shuffle(list_from_function)
print(list_from_function)
Keep in mind that shuffle operates in place and returns None. That means that if you try to print its return value, you get nothing.
You don't need to use for loop. You can pass argument to random.choices() indicating how many items you want.
import random
import string
letters = string.ascii_letters
numbers = string.digits
symbols = ['!', '#', '$', '%', '&', '(', ')', '*', '+']
# For demo, I hardcoded the numbers
nr_letters = 4
nr_symbols = 5
nr_numbers = 3
# create a list from randomly choosen characters
password_characters = random.choices(letters, k = nr_letters) \
+ random.choices(symbols, k = nr_symbols) \
+ random.choices(numbers, k = nr_numbers)
# shuffle the list:
random.shuffle(password_characters)
# convert the list to string
password = ''.join(password_characters)
Output:
>>> print(password)
>>> &J0*4oR!I3$!

Morse code decoder python function [duplicate]

This question already has answers here:
'Return' keyword returns only one element from a loop?
(3 answers)
Closed 6 years ago.
I'm trying to create a function that takes mores code as an input in string format and returns the message decoded also as a string.
I've identified that i need to split the string where there is a space to ascertain each individual character in morse. and a loop to return a value if matched in dictionary key. I'm a beginner and going really wrong somewhere. Thanks in advance.
code_dict = {'.-...': '&', '--..--': ',', '....-': '4', '.....': '5',
'...---...': 'SOS', '-...': 'B', '-..-': 'X', '.-.': 'R',
'.--': 'W', '..---': '2', '.-': 'A', '..': 'I', '..-.': 'F',
'.': 'E', '.-..': 'L', '...': 'S', '..-': 'U', '..--..': '?',
'.----': '1', '-.-': 'K', '-..': 'D', '-....': '6', '-...-': '=',
'---': 'O', '.--.': 'P', '.-.-.-': '.', '--': 'M', '-.': 'N',
'....': 'H', '.----.': "'", '...-': 'V', '--...': '7', '-.-.-.': ';',
'-....-': '-', '..--.-': '_', '-.--.-': ')', '-.-.--': '!', '--.': 'G',
'--.-': 'Q', '--..': 'Z', '-..-.': '/', '.-.-.': '+', '-.-.': 'C', '---...': ':',
'-.--': 'Y', '-': 'T', '.--.-.': '#', '...-..-': '$', '.---': 'J', '-----': '0',
'----.': '9', '.-..-.': '"', '-.--.': '(', '---..': '8', '...--': '3'
}
def decodeMorse(morseCode):
for item in morseCode.split(' '):
return code_dict.get(item)
my problem is it only decodes the first character of the string entered in morse
return something instantly ends the function. You stop stop processing input after first character.
In other languages, you could instead create list (array) with results, and return that:
def decodeMorse(morseCode):
results = []
for item in morseCode.split(' '):
results.append(code_dict.get(item))
return results
Or, as #Bakuriu suggested:
def decodeMorse(morseCode):
for item in morseCode.split(' '):
return [code_dict.get(item) for item in morseCode.split(' ')]
There is however simple flaw with this approach -- it decodes whole string at once, even if you only need first few characters.
We can do better in Python.
Use yield instead of return:
def decodeMorse(morseCode):
for item in morseCode.split(' '):
yield code_dict.get(item)
Now, the function instead of returning whole list at once, returns generator which yields one character at once. If you don't need whole translation, it's likely to be faster. It'll also use less memory (you don't need to construct and keep in memory list of all the characters).
You can convert the generator into list (list(decodeMorse('... --- ...'))) or into string (''.join(decodeMorse('... --- ...'))) if you need to. You can also just iterate over it like over a sequence:
>>> decoded = decodeMorse('... --- ...')
>>> for char in decoded:
... print(char)
...
S
O
S
>>>
...except, you can only do it once:
>>> for char in decoded:
... print(char)
...
>>>
...because generators are disposable.
If you need to iterate over it another time, store it in list, or create another generator by calling decodeMorse again.

pyparsing: setResultsName for multiple elements get combined

Here is the text I'm parsing:
x ~ normal(mu, 1)
y ~ normal(mu2, 1)
The parser matches those lines using:
model_definition = Group(identifier.setResultsName('random_variable_name') + '~' + expression).setResultsName('model_definition')
// end of line: .setResultsName('model_definition')
The problem is that when there are two model definitions, they aren't named separately in the ParseResults object:
It looks like the first one gets overridden by the second. The reason I'm naming them is to make executing the lines easier - this way I (hopefully) don't have to figure out what is going on at evaluation time - the parser has already labelled everything. How can I get both model_definitions labelled? It would be nice if model_definition held a list of every model definition found.
Just in case, here is some more of my code:
model_definition = Group(identifier.setResultsName('random_variable_name') + '~' + expression).setResultsName('model_definition')
expression << Or([function_application, number, identifier, list_literal, probability_expression])
statement = Optional(newline) + Or([model_definition, assignment, function_application]) + Optional(newline)
line = OneOrMore('\n').suppress()
comment = Group('#' + SkipTo(newline)).suppress()
program = OneOrMore(Or([line, statement, comment]))
ast = program.parseString(input_string)
return ast
Not documented that I know of, but I found something in pyparsing.py:
I changed .setResultsName('model_definition') to .setResultsName('model_definition*') and they listed correctly!
Edit: it is documented, but it is a flag you pass to setResultsName:
setResultsName( string, listAllMatches=False ) - name to be given to tokens matching the element; if multiple tokens within a repetition group (such as ZeroOrMore or delimitedList) the default is to return only the last matching token - if listAllMatches is set to True, then a list of matching tokens is returned.
Here is enough of your code to get things to work:
from pyparsing import *
# fake in the bare minimum to parse the given test strings
identifier = Word(alphas, alphanums)
integer = Word(nums)
function_call = identifier + '(' + Optional(delimitedList(identifier | integer)) + ')'
expression = function_call
model_definition = Group(identifier.setResultsName('random_variable_name') + '~' + expression)
sample = """
x ~ normal(mu, 1)
y ~ normal(mu2, 1)
"""
The trailing '*' is there in setResultsName for those cases where you use the short form of setResultsName: expr("name*") vs expr.setResultsName("name", listAllMatches=True). If you prefer calling setResultsName, then I would not use the '*' notation, but would pass the listAllMatches argument.
If you are getting names that step on each other, you may need to add a level of Grouping. Here is your solution using listAllMatches=True, by virtue of the trailing '*' notation:
model_definition1 = model_definition('model_definition*')
print OneOrMore(model_definition1).parseString(sample).dump()
It returns this parse result:
[['x', '~', 'normal', '(', 'mu', '1', ')'], ['y', '~', 'normal', '(', 'mu2', '1', ')']]
- model_definition: [['x', '~', 'normal', '(', 'mu', '1', ')'], ['y', '~', 'normal', '(', 'mu2', '1', ')']]
[0]:
['x', '~', 'normal', '(', 'mu', '1', ')']
- random_variable_name: x
[1]:
['y', '~', 'normal', '(', 'mu2', '1', ')']
Here is a variation that does not use listAllMatches, but adds another level of Group:
model_definition2 = model_definition('model_definition')
print OneOrMore(Group(model_definition2)).parseString(sample).dump()
gives:
[[['x', '~', 'normal', '(', 'mu', '1', ')']], [['y', '~', 'normal', '(', 'mu2', '1', ')']]]
[0]:
[['x', '~', 'normal', '(', 'mu', '1', ')']]
- model_definition: ['x', '~', 'normal', '(', 'mu', '1', ')']
- random_variable_name: x
[1]:
[['y', '~', 'normal', '(', 'mu2', '1', ')']]
- model_definition: ['y', '~', 'normal', '(', 'mu2', '1', ')']
- random_variable_name: y
In both cases, I see the full content being returned, so I don't quit understand what you mean by "if you return multiple, it fails to split out each child."

Separating strings (list elements) with many spliters without loosing spliter from list

I want to separate list elements if list element contain any value from
list_operators = ['+', '-', '*', '(', ')']
without losing operator from list and without using regex.
For instance:
my_list = ['a', '=', 'x+y*z', '//', 'moo']
Wanted output :
['a', '=', 'x', '+', 'y', '*', 'z', '//', 'moo']
and x y z are words not one character:
['john+doe/12*5']
['john','+','doe','/','12','*','5']
You can use itertools.groupby() to achieve this:
from itertools import groupby
operators = {'+', '-', '*', '(', ')'}
fragments = ['a', '=', 'x+y*z', '//', 'moo', '-', 'spam*(eggs-ham)']
separated = []
for fragment in fragments:
for is_operator, group in groupby(fragment, lambda c: c in operators):
if is_operator:
separated.extend(group)
else:
separated.append(''.join(group))
>>> separated
['a', '=', 'x', '+', 'y', '*', 'z', '//', 'moo', '-',
'spam', '*', '(', 'eggs', '-', 'ham', ')']
Note that I've changed the names of your variables to be a little more meaningful, and made operators a set because we only care about membership, not order (although the code would work just as well, if a little more slowly, with a list).
groupby() returns an iterable of (key, group) pairs, starting a new group whenever key changes. Since I've chosen a key function (lambda c: c in operators) that just tests for a character's membership in operators, the result of the groupby() call looks something like this:
[
(False, ['s', 'p', 'a', 'm']),
(True, ['*', '(']),
(False, ['e', 'g', 'g', 's']),
(True, ['-']),
(False, ['h', 'a', 'm']),
(True, [')'])
]
(groupby() actually returns a groupby object made up of (key,grouper object) tuples - I've converted those objects to lists in the example above for clarity).
The rest of the code is straightforward: if is_operator is True, the characters in group are used to extend separated; if it's False, the characters in group are joined back into a string and appended to separated.
This is an easy way of doing it:
for x in my_list:
if len(set(list_operators) & set(list(x)))!=0:
for i in list(x):
slist.append(i)
else:
slist.append(x)
slist
['a', '=', 'x', '+', 'y', '*', 'z', '//', 'moo']
You can also do something like this:
import re
from itertools import chain
list_operators = ['+', '-', '*', '(', ')']
tokenizer = re.compile(r"[{}]|\w+".format("".join(map(re.escape, list_operators))))
my_list = ['a', '=', 'x+y*z', '//', 'moo', 'john+doe/12*5']
parsed = list(chain.from_iterable(map(tokenizer.findall, my_list)))
parsed result:
['a', 'x', '+', 'y', '*', 'z', 'moo', 'john', '+', 'doe', '12', '*', '5']

Splitting a list in python

I'm writing a parser in Python. I've converted an input string into a list of tokens, such as:
['(', '2', '.', 'x', '.', '(', '3', '-', '1', ')', '+', '4', ')', '/', '3', '.', 'x', '^', '2']
I want to be able to split the list into multiple lists, like the str.split('+') function. But there doesn't seem to be a way to do my_list.split('+'). Any ideas?
Thanks!
You can write your own split function for lists quite easily by using yield:
def split_list(l, sep):
current = []
for x in l:
if x == sep:
yield current
current = []
else:
current.append(x)
yield current
An alternative way is to use list.index and catch the exception:
def split_list(l, sep):
i = 0
try:
while True:
j = l.index(sep, i)
yield l[i:j]
i = j + 1
except ValueError:
yield l[i:]
Either way you can call it like this:
l = ['(', '2', '.', 'x', '.', '(', '3', '-', '1', ')', '+', '4', ')',
'/', '3', '.', 'x', '^', '2']
for r in split_list(l, '+'):
print r
Result:
['(', '2', '.', 'x', '.', '(', '3', '-', '1', ')']
['4', ')', '/', '3', '.', 'x', '^', '2']
For parsing in Python you might also want to look at something like pyparsing.
quick hack, you can first use the .join() method to join create a string out of your list, split it at '+', re-split (this creates a matrix), then use the list() method to further split each element in the matrix to individual tokens
a = ['(', '2', '.', 'x', '.', '(', '3', '-', '1', ')', '+', '4', ')', '/', '3', '.', 'x', '^', '2']
b = ''.join(a).split('+')
c = []
for el in b:
c.append(list(el))
print(c)
result:
[['(', '2', '.', 'x', '.', '(', '3', '-', '1', ')'], ['4', ')', '/', '3', '.', 'x', '^', '2']]

Categories

Resources