Passing array contents into function not working correctly - python

When trying to pass an array into a function it doesn't do anything at all. My code is below
main.py
import items
import npcs.py
def pickup(item):
global player_weight_max,player_weight,player_inv
#Calculates if item's weight will make player_weight go over player_weight_max
if player_weight + item[5] <= player_weight_max:
player_inv.append(item)
player_weight = player_weight + item[5]
else:
print("You're not able to carry this item.")
def npc(npc):
#Prints NPC speech
if npc[2] != None:
print("".join(npc[1]) + ": " + "".join(npc[2]))
else:
pass
for function in npc[3]:
if function[0] == 'pickup':
pickup(function[1])
if function[0] == 'battle':
battle(function[1])
npcs.py
import items
#art,name,speech,functions
test_guy = [["art"],["name"],["speech"],[
[['pickup'],[items.armour[0]],
[['pickup'],[items.armour[1]],
]
]
items.py
armour = [
[str(""),str("Tin Helmet"),int(1),int(20),str("head"),int(2),int(0),int(2)],
[str(""),str("Tin Chestplate"),int(1),int(20),str("torso"),int(0),int(1),int(2)],
[str(""),str("Tin Pants"),int(1),int(20),str("legs"),int(3),int(0),int(2)],
[str(""),str("Tin Boots"),int(1),int(20),str("feet"),int(2),int(0),int(2)],
]
Why is pickup() not appending the information obtained from items.py
I have already verified pickup() works when doing pickup(items.armour[0]) which should just be passing the array at that location into pickup(), why can the same not be done with the information contained in test_guy[3][0] and test_guy[3][1]?
updated the code as follows:
def npc(npc):
#Prints NPC speech
if npc[2] != None:
print("".join(npc[1]) + ": " + "".join(npc[2]))
else:
pass
for function in npc[3]:
print(function[1][0])
if function[0][0] == 'pickup':
pickup(function[1][0])
if function[0][0] == 'battle':
battle(function[1][0])
upon running:
npc(npcs.test_guy)
print(player_inv)
the output is now correct:
name: speech
['', 'Tin Helmet', 1, 20, 'head', 2, 0, 2]
['', 'Tin Chestplate', 1, 20, 'torso', 0, 1, 2]
[['', 'Tin Helmet', 1, 20, 'head', 2, 0, 2], ['', 'Tin Chestplate', 1, 20, 'torso', 0, 1, 2]]
Thank you!
(Yes I know this is not the most efficient way to do things, I'm still learning and just trying to get things working for now)

Whilst avoiding the unnecessary complexity of this code..
Your items are within another array so item[0] will never equal pickup/battle and equally, item[1] will never be the item, it will be an array with an item.
So first fix the missing brackets of your functions part of test_guy, and then reference the functions inner array first
item[0][0] and item[0][1]

Related

Printing multiple list in a for loop

Hello I am trying to create the table below by using list. The product s and the prices are already in lists (priceList and productList). i have successfully created new more list where the person types in the product code and quantity (quan_inputed).
Any help would be greatly appreciated as I don't know what to do. I have tried several methods already and this is the closest I've come to getting multiple inputs at once.
Thank you
Try This:
def add_item():
code_inputed = []
quan_inputed = []
while True:
i = input("enter code: ")
if i != "END":
q = input("enter quantity: ")
code_inputed.append(int(i))
quan_inputed.append(int(q))
else:
break
return code_inputed,quan_inputed
def showRecord(code_inputed, quan_inputed):
product_info = {}
for kk in range(len(code_inputed)):
quan = quan_inputed[kk]
kk = code_inputed[kk]
price = priceList[kk]
product = productList[kk]
if kk not in product_info:
product_info[kk] = [kk, quan, price, product]
else:
product_info[kk][1] += quan
product_info[kk][2] = product_info[kk][1] * price
for x in ["Code", "Quanity", "Price", "Product"]:
print(x, end=" ")
print()
for x in product_info:
for info in product_info[x]:
print(info, end=" ")
print()
code_inputed, quan_inputed = add_item()
showRecord(code_inputed, quan_inputed)
Just to explain my comment about the other approach, I recommend storing the data in other way than just in multiple lists. For example like this:
items = [
{'code': 2, 'price': 39.95, 'quantity': 11, 'product': "Tea Set\t\t"},
{'code': 34, 'price': 19.95, 'quantity': 3, 'product': "Citrus Cather"}
]
print("Code\tProduct\t\t\tPrice $\tQuantinty\tCost $")
print("------------------------------------------------------")
for item in items:
print(f"{item.get('code')}\t\t{item.get('product')}\t{item.get('price')}\t{item.get('quantity')}\t\t\t{item.get('price') * item.get('quantity')}")
Those tabs (\t) in product name in dictionary are just to make the table nice, you should come up with nicer way to print it...
Result:

I'm a complete beginner! How to I convert a .txt file (film script) to a table (characters and lines) in R or Python?

I'm a complete beginner, and for a project for college I need to analyse film scripts. I want to create a table in which I can match the characters to their lines. My files are all in .txt format and I'd like to convert them to a csv file. I have a lot of scripts to go through, so I'd like to find a code that can be easily adapted to the different files.
This is what I have:
THREEPIO
Did you hear that? They've shut
down the main reactor. We'll be
destroyed for sure. This is
madness!
THREEPIO
We're doomed!
THREEPIO
There'll be no escape for the
Princess this time.
THREEPIO
What's that?
And this is what I need to have:
"character" "dialogue"
"1" "THREEPIO" "Did you hear that? They've shut down the main reactor. We'll be destroyed for sure. This is madness!"
"2" "THREEPIO" "We're doomed!"
"3" "THREEPIO" "There'll be no escape for the Princess this time."
"4" "THREEPIO" "What's that?"
This is what I've tried:
# the first 70 lines don't contain dialogues
# so we can start reading at line 70 (for instance)
i = 70
# while loop to extract character and dialogues
# (probably there's a better way to parse the file instead of
# using my crazy nested if-then-elses, but this works for me)
while (i <= nlines)
{
# if empty line
if (sw[i] == "") i = i + 1 # next line
# if text line
if (sw[i] != "")
{
# if uninteresting stuff
if (substr(sw[i], 1, 1) != " ") {
i = i + 1 # next line
} else {
if (nchar(sw[i]) < 10) {
i = i + 1 # next line
} else {
if (substr(sw[i], 1, 5) != " " && substr(sw[i], 6, 6) != " ") {
i = i + 1 # next line
} else {
# if character name
if (substr(sw[i], 1, 30) == b30)
{
if (substr(sw[i], 31, 31) != " ")
{
tmp_name = substr(sw[i], 31, nchar(sw[i], "bytes"))
cat("\n", file="EpisodeVI_dialogues.txt", append=TRUE)
cat(tmp_name, "", file="EpisodeVI_dialogues.txt", sep="\t", append=TRUE)
i = i + 1
} else {
i = i + 1
}
} else {
# if dialogue
if (substr(sw[i], 1, 15) == b15)
{
if (substr(sw[i], 16, 16) != " ")
{
tmp_diag = substr(sw[i], 16, nchar(sw[i], "bytes"))
cat("", tmp_diag, file="EpisodeVI_dialogues.txt", append=TRUE)
i = i + 1
} else {
i = i + 1
}
}
}
}
}
}
}
}
Any help would me much appreciated! Thank you!!
You can do something like this:
text = """
THREEPIO
Did you hear that? They've shut
down the main reactor. We'll be
destroyed for sure. This is
madness!
THREEPIO
We're doomed!
THREEPIO
There'll be no escape for the
Princess this time.
THREEPIO
What's that?
"""
clean = text.split()
n = 1
tmp = []
results = []
for element in clean:
if element.isupper():
if tmp:
results.append(tmp)
tmp = [n, element]
n += 1
continue
try:
tmp[2] = " ".join((tmp[2], element))
except IndexError:
tmp.append(element)
print(results)
Results :
[[1, 'THREEPIO', "Did you hear that? They've shut down the main reactor. We'll be destroyed for sure. This is madness!"], [2, 'THREEPIO', "We're doomed!"], [3, 'THREEPIO', "There'll be no escape for the Princess this time."]]
if you know the list of character names (and are not worried about spelling errors) something like this would work:
script = """
THREEPIO
Did you hear that? They've shut
down the main reactor. We'll be
destroyed for sure. This is
madness!
THREEPIO
We're doomed!
THREEPIO
There'll be no escape for the
Princess this time.
THREEPIO
What's that?
"""
characters = ['THREEPIO', 'ANAKIN']
lines = [x for x in list(map(str.strip, script.split('\n'))) if x]
results = []
for (i, item) in enumerate(lines):
if item in characters:
dialogue = []
for index in range(i + 1, len(lines)):
if lines[index] in characters:
break
dialogue.append(lines[index])
results.append([item, ' '.join(dialogue)])
print([x for x in enumerate(results, start=1)])
this prints:
[(1, ['THREEPIO', "Did you hear that? They've shut down the main reactor. We'll be destroyed for sure. This is madness!"]), (2, ['THREEPIO', "We're doomed!"]), (3, ['THREEPIO', "There'll be no escape for the Princess this time."]), (4, ['THREEPIO', "What's that?"])]

Python3 - Adding User Response to a List Instead of Over-writing Existing Data

I am trying to write a basic store-front script that loops until the customer says no to the question. Each time there's input of an Item Number, I'm trying to store it and then eventually be able to match those numbers up with the Item Name and the Price (not quite yet, though)...
I am just, now, trying to get it to add to the empty list "item_nums" instead of adding the last entry and over-writing the previous numbers.
STOREKEEPER
products = ['Notebook', 'Atari', 'TrapperKeeper', 'Jeans', 'Insects',
'Harbormaster', 'Lobotomy', 'PunkRock', 'HorseFeathers', 'Pants',
'Plants', 'Salami']
prices = ['$4.99', '$99.99', '$89.99', '$3.99', '$2.99', '$299.99',
'$19.99', '$3.99', '$4.99', '$2.99', '$119.99', '$1.99']
SKUs = [1, 2, 3, 4, 5, 6, 7, 8 ,9, 10, 11, 12]
item_nums = ()
quantity = []
response = ''
#MORE VARIABLES AND FUNCTIONS WILL GO HERE
print("Jay's House of Rip-Offs\n\n")
titles = ['Item Number', 'Item Name', 'Price']
data = [titles] + list(zip(SKUs, products, prices))
for i, d in enumerate(data):
line = '|'.join(str(x).ljust(16) for x in d)
print(line)
if i == 0:
print('-' * len(line))
response = str(input("Order products [Y / N]?: "))
while response != 'N':
item_nums = input("Enter an item number: ")
SKUs.append(item_nums)
response = str(input("Order products [Y / N]?: "))
if response == 'N':
break
print("Here is the list of items you ordered: ",item_nums[0])
I'm not sure why you're appending to SKU, you need a new list to track order numbers.
orders = []
while str(input("Order products [Y / N]?: ")) != 'N':
item_nums = input("Enter an item number: ")
orders.append(item_nums)
print("Here is the list of items you ordered: ", orders)

Text to cleaner text to excel spreadsheet project

I have a text file full of pc data, organized as a list of blocks of one of two types. Either:
*redacted*
My goal was to have Python (3.6.2) open and read the file, clean it up, and compile the data into an excel spreadsheet as follows:
Column 1: PC name
Column 2: Error Type (0 if none, 1-4 for 4 error types)
Column 3: ID (if no error, no braces containing the ID)
Column 4: Password (if no error, just the password)
Here is my code. I use Pycharm, and am in a virtual env:
import xlsxwriter
workbook = xlsxwriter.Workbook('Computer Data.xlsx')
worksheet = workbook.add_worksheet()
bold = workbook.add_format({'bold': True})
left = workbook.add_format({'align': 'justify'})
worksheet.set_column(0, 0, 14)
worksheet.set_column(1, 1, 5)
worksheet.set_column(2, 2, 38)
worksheet.set_column(3, 3, 55)
worksheet.write('A1', 'Name', bold)
worksheet.write('B1', 'Error', bold)
worksheet.write('C1', 'ID', bold)
worksheet.write('D1', 'Password', bold)
def nonblank_lines(f):
for l in f:
line = l.rstrip()
if line:
yield line.lstrip
with open("C:\\Users\\MyName\\Desktop\\BLRP.txt", "r+") as op:
gold_lst = []
nonblank = nonblank_lines(op)
for line in nonblank:
if line.startswith("Computer Name"):
gold_lst.append(str(line))
gold_lst.append("NO ERROR")
elif line.startswith("ID"):
gold_lst.append("IDG: " + str(line))
gold_lst.append('NO ERROR')
elif line.startswith("ERROR: An error occurred while"):
gold_lst.append('1')
gold_lst.append(str('ID: {' + line + '}'))
gold_lst.append(str('Password: '))
elif line.startswith("ERROR: No key"):
gold_lst.append('2')
gold_lst.append(str('ID: {' + line + '}'))
gold_lst.append(str('Password: '))
elif line.startswith("ERROR: An error occurred (code 0x80070057)"):
gold_lst.append('3')
gold_lst.append(str('ID: {' + line + '}'))
gold_lst.append(str('Password: '))
elif line.startswith("ERROR: An error occurred (code 0x8004100e)"):
gold_lst.append('4')
gold_lst.append(str('ID: {' + line + '}'))
gold_lst.append(str('Password: '))
elif line.startswith("Password"):
gold_lst.append(str('Password: ' + next(nonblank)))
print(gold_lst)
op.close()
pc_data = (gold_lst)
row = 1
col = 0
for obj in pc_data:
if obj.startswith("Computer Name"):
worksheet.write_string(row, col, obj[15:])
elif obj.startswith('NO'):
worksheet.write_number(row, col + 1, 0, left)
elif obj.startswith('1'):
worksheet.write_number(row, col + 1, int(obj), left)
elif obj.startswith('2'):
worksheet.write_number(row, col + 1, int(obj), left)
elif obj.startswith('3'):
worksheet.write_number(row, col + 1, int(obj), left)
elif obj.startswith('4'):
worksheet.write_number(row, col + 1, int(obj), left)
elif obj.startswith("ID: {ERROR"):
worksheet.write_string(row, col + 2, '')
elif obj.startswith("IDG: "):
worksheet.write_string(row, col + 2, obj[10:-1])
elif obj.startswith("Password"):
worksheet.write_string(row, col + 3, obj[9:])
row += 1
workbook.close()
Now, this works perfectly for the file in question, but, in addition to the terribly suboptimal code, I'm sure, there is something I can explicitly see that needs improved. In this block:
if line.startswith("Computer Name"):
gold_lst.append(str(line))
gold_lst.append("NO ERROR")
I only want "NO ERROR" to be appended to my list if my line starts with "Computer Name" AND the next non-blank line does not begin with "ERROR." Naturally, I tried this:
if line.startswith("Computer Name"):
if next(nonblank).startswith("ERROR"):
gold_lst.append(str(line))
elif next(nonblank).startswith("VOLUME"):
gold_lst.append(str(line))
gold_lst.append("NO ERROR")
The problem is, this creates a jacked up excel spreadsheet, and I don't at all know why. Even in the step afterward in the main code where I print gold_lst (just to check if the list is correct), the list is terribly inaccurate. I can't even seem to figure out of what the list is comprised.
How can I fix this?
As for a second question, if I may ask it in the same topic, more general text files of this type which I am likely to receive in the future may contain computers with more than one ID and password. The block would look like this, if I had to guess:
*redacted*
And there may be even more than 2 such ID/Password combos. How can I modify my code to allow for this? As it stands, my code will not easily account for this. I am quite new to Python, so maybe it could, but I don't see it.
One approach to this problem is as follows:
Read in the whole file, skipping any empty lines.
Use Python's groupby() function to split the list of lines into blocks based on the Computer Name line.
For each block, try and extract both an error and a list of IDs and Passwords. Leave blank if not present.
For each block, write any extracted data to the next row in the spreadsheet.
The script is as follows:
from itertools import groupby
import xlsxwriter
import re
workbook = xlsxwriter.Workbook('Computer Data.xlsx')
worksheet = workbook.add_worksheet()
bold = workbook.add_format({'bold': True})
left = workbook.add_format({'align': 'justify'})
cols = [('Name', 14), ('Error', 5), ('ID1', 38), ('Password1', 55), ('ID2', 38), ('Password2', 55), ('ID3', 38), ('Password3', 55)]
for colx, (heading, width) in enumerate(cols):
worksheet.write_string(0, colx, heading, bold)
worksheet.set_column(colx, colx, width)
rowy = 1
lines = []
data = []
computer_name = None
with open('BLRP.txt') as f_input:
lines = [line.strip() for line in f_input if len(line.strip())]
for k, g in groupby(lines, lambda x: x.startswith("Computer Name:")):
if k:
computer_name = re.search(r'Computer Name:\s*(.*)\s*', list(g)[0]).group(1)
elif computer_name:
block = list(g)
error = 'NO ERROR'
ids = []
passwords = []
for line_number, line in enumerate(block):
re_error = re.match('ERROR:\s+"(.*?)"', line)
if re_error:
error = re_error.group(1)
if line.startswith('Numerical Password:'):
ids.append(re.search('\{(.*?)\}', block[line_number+1]).group(1))
passwords.append(block[line_number+3].strip())
worksheet.write_string(rowy, 0, computer_name)
worksheet.write_string(rowy, 1, error)
for index, (id, pw) in enumerate(zip(ids, passwords)):
worksheet.write_string(rowy, index * 2 + 2, id)
worksheet.write_string(rowy, index * 2 + 3, pw)
rowy += 1 # Advance to the next output row
workbook.close()
Assuming your BLRP.txt is as follows:
Computer Name: "Name Here1"
ERROR: "some type of error"
Blah blah
Blah blah
Blah blah
Computer Name: "Name Here2"
Volume blah blah
Blah Blah
Numerical Password:
ID: {"The ID1 is here; long string of random chars"}
Password:
"Password1 here; also a long string"
Blah Blah
Blah Blah
Numerical Password:
ID: {"The ID2 is here; long string of random chars"}
Password:
"Password2 here; also a long string"
Blah Blah
Blah Blah
Numerical Password:
ID: {"The ID3 is here; long string of random chars"}
Password:
"Password3 here; also a long string"
Blah Blah
Blah Blah
You would get a spreadsheet as follows:
How does groupby() work?
Normally when you iterate over a list, it gives you the entries one item at a time. With groupby(), you are able to iterate over this list in "groups", where the number of items in each group is based on a condition. The condition is provided in the form of a function (I have used lambda to avoid writing a separate function).
groupby() will build up the group of items to return until the result from the function changes. In this case, the function is looking for lines that start with the word Computer Name. So when that is true it will return with one item (unless there are two adjacent lines with Computer Name on them). Next it will return with all the lines that don't start with Computer Name, and so on.
It returns two things, a key and a group. The key is the result of the function startswith(), which will either be True or False. The group is an iterable holding all the matching items. list(g) is used to convert it into a normal list, in this case all the lines until the next Computer Name line is returned.
To write the entries onto different rows and to convert known error messages into numbers:
from itertools import groupby
import xlsxwriter
import re
workbook = xlsxwriter.Workbook('Computer Data.xlsx')
worksheet = workbook.add_worksheet()
bold = workbook.add_format({'bold': True})
left = workbook.add_format({'align': 'justify'})
cols = [('Name', 14), ('Error', 5), ('ID', 38), ('Password', 55)]
for colx, (heading, width) in enumerate(cols):
worksheet.write_string(0, colx, heading, bold)
worksheet.set_column(colx, colx, width)
rowy = 1
lines = []
data = []
computer_name = None
error_numbers = {
'An error occurred while connecting to the BitLocker management interface.' : 1,
'No key protectors found.' : 2,
'An error occurred (code 0x80070057):' : 3,
'An error occurred (code 0x8004100e):' : 4}
with open('BLRP.txt') as f_input:
lines = [line.strip() for line in f_input if len(line.strip())]
for k, g in groupby(lines, lambda x: x.startswith("Computer Name:")):
block = list(g)
if k:
computer_name = re.search(r'Computer Name:\s*(.*)\s*', block[0]).group(1)
elif computer_name:
error_number = 0 # 0 for NO ERROR
ids = []
passwords = []
for line_number, line in enumerate(block):
re_error = re.match('ERROR:\s+?(.*)\s*?', line)
if re_error:
error = re_error.group(1)
error_number = error_numbers.get(error, -1) # Return -1 for an unknown error
if line.startswith('Numerical Password:'):
ids.append(re.search('\{(.*?)\}', block[line_number+1]).group(1))
passwords.append(block[line_number+3].strip())
worksheet.write_string(rowy, 0, computer_name)
worksheet.write_number(rowy, 1, error_number)
for id, pw in zip(ids, passwords):
worksheet.write_string(rowy, 0, computer_name)
worksheet.write_number(rowy, 1, error_number)
worksheet.write_string(rowy, 2, id)
worksheet.write_string(rowy, 3, pw)
rowy += 1 # Advance to the next output row
if len(ids) == 0:
rowy += 1 # Advance to the next output row
workbook.close()

Setting row Span in QTableView using Python?

I am trying to set rowspan on second column of my QTableView but somehow logically i am missing something. i am only able to get A and B but not C. Plus i am getting warning QTableView::setSpan: span cannot overlap and QTableView::setSpan: single cell span won't be added
My code snippet is:-
startspan = 0
for i, tcname in enumerate(tcfilename):
if tcfilename[i]:
if i > 0:
print '#######################'
print 'startspan = '+str(startspan)+' i = '+str(i)
if tcname == tcfilename[i-1]:
#setSpan (row, column, rowSpan, columnSpan)
print 'if (from_row, till_row) '+str(startspan)+' '+str(i)
table_view.setSpan(startspan, 1, i, 1);
elif tcname != tcfilename[i-1]:
print 'Else no span (from_row, till_row) '+str(startspan)+' '+str(i)
table_view.setSpan(startspan, 1, i, 1);
if i == 1:
startspan = 0
else:
startspan = i
else:
break
Did this with simple two line code below
for toRow, tcname in enumerate(tcfilename):
table_view.setSpan(tcfilename.index(tcname), 1, tcfilename.count(tcname), 1)
I made a nifty little function to solve this.. Had recursion but then optimized it without recursion.. feed it a table and a data set
def my_span_checker(self, my_data, table):
for i in range(len(my_data)):
my_item_count = 0
my_label = table.item(i, 0).text()
for j in range(len(my_data)):
if table.item(j, 0).text() == my_label:
my_item_count += 1
if my_item_count != 1:
table.setSpan(i, 0, my_item_count, 1)

Categories