I'm aiming to display records of employees with a salary between 2 user inputted values (in a format specified in my function printTuple(data)). So far I use the function choice2() to open the file, read line by line in a for loop, convert the line (which is a string) to an int, then grab the index of the salary so I can compare it to the 2 inputted values (. After that I take the line as a variable in "record" and go to makeTuple to turn it into a tuple, and then finally print it in my desired format inside printTuple.
When I attempt to run the choice2 function I get an error: "local variable 'myTuple' referenced before assignment". However I need to change the myTuple value to an int before I can compare it with the values the user inputted, so I'm not sure how to fix this.
Here is my program:
def makeTuple (employee):
myTuple = employee.split(" ")
(payroll, salary, job_title, *othernames, surname) = myTuple
return(myTuple)
def printTuple (data):
employee_str = "{:<15} {:20} {:<10} {:<15} £{:>1}"
print(employee_str.format(data[-1]+ ",", " ".join(data[3:-1]), data[0], data[2], data[1]))
def choice1():
op_1 = str(input("Please enter a Pay Roll number: "))
file = open(path)
lines = file.readlines()
for line in lines:
if op_1 in line:
record = line.strip()
myTuple = makeTuple(record)
printTuple(myTuple)
def choice2():
op_2a = int(input("Please enter a lower bound for the Salary :"))
op_2b = int(input("Please enter a higher bound for the Salary :"))
file = open(path)
lines = file.readlines()
for line in lines:
myTuple[0] = int(myTuple[0])
if myTuple[0] >= op_2a and myTuple[0] <= op_2b:
myTuple[0] = myTuple[0]
record = line.strip()
myTuple = makeTuple(record)
print(myTuple)
get_file = input(str("Please enter a filename: "))
path = get_file + ".txt"
try:
f = open(path)
except IOError:
print('The file could not be opened.')
exit()
for line in iter(f):
record = line.strip()
myTuple = makeTuple(record)
printTuple(myTuple)
print("\n\nDisplay full details of an Employee with a given payroll number enter: '1'")
print("Display all employees with a salary within a specified range, enter: '2'")
print("Display the first and last name of all employees with a job title, enter: '3'")
print("Quit Program: '4'")
choice = int(input("Choose an option from 1-4: "))
while choice != 1 and choice != 2 and choice != 3 and choice != 4:
print("Incorrect Value, please choose a number from 1-4")
print("\n\nDisplay full details of an Employee with a given payroll number enter: '1'")
print("Display all employees with a salary within a specified range, enter: '2'")
print("Display the first and last name of all employees with a job title, enter: '3'")
print("Quit Program: '4'")
choice = int(input("Choose an option from 1-4: "))
if choice == 1:
choice1()
if choice == 2:
choice2()
if choice == 3:
choice3()
if choice == 4:
exit()
This is the text file I am reading from:
12345 55000 Consultant Bart Simpson
12346 25000 Teacher Ned Flanders
12347 20000 Secretary Lisa Simpson
12348 20000 Wizard Hermione Grainger
12349 30000 Wizard Harry Potter
12350 15000 Entertainer Herschel Shmoikel Krustofski
13123 75000 Consultant Zlatan Ibrahimovic
13124 150000 Manager Gareth Southgate
13125 75000 Manager Juergen Klopp
13126 35000 Lecturer Mike T Sanderson
13127 200000 Entertainer Adele Laurie Blue Adkins
13128 50 Timelord Peter Capaldi
13129 250000 Entertainer Edward Christopher Sheeran
13130 32000 Secretary Wilma Flintstone
Any help is appreciated, thanks in advance.
Your error message (local variable myTuple referenced before assignment) points out the required solution. I have:
reordered (record = line.strip() and myTuple = makeTuple(record) to top of loop)
renamed some variables (myTuple is not very descriptive, and is actually a list anyway, better naming makes code much easier to read and reason about)
heavily commenting (I would not normally comment my own code this much, more as indications of what I have done and why)
Here is the updated code for choice2
def choice2():
lower_bound = int(input("Please enter a lower bound for the Salary :")) # Renamed for clarity
upper_bound = int(input("Please enter a higher bound for the Salary :")) # Renamed for clarity
# The following two lines are repeated multiple times, you should probably read
# the file once and store into a list (or better yet a dictionary
# keyed with pay roll number) and pass it into the function.
file = open(path)
lines = file.readlines()
for line in lines:
record = line.strip()
employee_details = makeTuple(record) # Rename muTuple to employee_details
# OR MORE SIMPLY employee_details = makeTuple(line.strip())
# Now we have the variable we can work with it
salary = int(employee_details[0]) # The only thing we do with the tuple is print it, so no need to modify it
if salary >= lower_bound and salary <= upper_bound:
# This does nothing, so deleted - myTuple[0] = myTuple[0]
print(employee_details) # Or more likely you want to use your custom print function printTuple(employee_details)
Related
I am attempting to make some code that will take a persons height, convert it into feet and store it in a txt file.
def rollercoaster():
name = input("what is your name?: ")
heightCM = int(input("enter your height in cm: "))
ft = (heightCM / 30.48)
print(f"you are {ft} foot tall.")
if ft < 5.5:
booklist = open("booklist.txt", "a")
booklist.write(name)
booklist.write(" ")
booklist.write("NOT TALL ENOUGH.")
booklist.close()
if ft > 5.5:
booklist = open("booklist.txt", "a")
booklist.write(name)
booklist.write(" ")
booklist.write("TALL ENOUGH.")
booklist.close()
I would like to make it so if your name that you input is already in the txt file, it will see if you're tall enough for the rollercoaster.
Open your file and scan it for the names. Otherwise, append.
def rollercoaster():
name = input("what is your name?: ")
heightCM = int(input("enter your height in cm: "))
ft = (heightCM / 30.48)
print(f"you are {ft} foot tall.")
found = None
with open("booklist.txt") as f:
for line in f:
if line.startswith(name):
found = line
break
if found is not None:
print(found)
else:
with open("booklist.txt", "a") as booklist:
if ft < 5.5:
booklist.write(f'{name} NOT TALL ENOUGH\n')
else:
booklist.write(f'{name} TALL ENOUGH\n')
However, as mentioned in the comments, JSON would make more sense than scanning lines.
For example, mapping names to heights (in cm)
{
"alice": 158,
"bob": 172
}
Then read that, and perform the conversion and check if they are tall enough or not (there is no need to store whether or not they are tall enough in the file itself).
I really do not know how to describe this but I'll include an output in preformatted text after my horrific explanation.
So... I create three lists I need to use two, 'employeeSold' and 'employeeName,' however I need to merge/align the two so I can make a ranking system on who's got the most, I figured out how to order from largest to most significant for employeeSold, but I am most unsure on how to link the correct Name to the correct value, I figured it needs to come before the ordering though, but I really do not know what to type and I've spent a handful of hours thinking about it.
Here is an example OUTPUT of what I want for this code:
Ranking:
John - 5
Laura - 4
BOJO -1
It has assigned each integer (employeeSold) to each string (employeeName) and then ordered the integers (employeeSold) inserted by the user from largest to most significant and then printed their names next to their integer.
Here is my code:
def employee():
employeeName = input("What is Employee's name?: ")
employeeID = input("What is Employee's ID?: ")
employeeSold = int(input("How many houses employee sold?: "))
nameList.append(employeeName)
idList.append(employeeID)
soldList.append(employeeSold)
nextEmployee = input("Add another employee? Type Yes or No: ")
if nextEmployee == "2":
employee()
else:
print("Employee Names:")
print(", ".join(nameList))
print("Employee's ID: ")
print(", ".join(idList))
print("Employee Sold:")
print( " Houses, ".join( repr(e) for e in soldList ), "Houses" )
print("Commission: ")
employeeCommission = [i * 500 for i in soldList]
print(", ".join( repr(e) for e in employeeCommission ), "" )
print("Commission Evaluation: ")
totalCommission = sum(employeeCommission)
print(totalCommission)
soldList.sort(reverse=True)
print("Employee Ranking: ")
ranking = (", ".join( repr(e) for e in soldList))
print(ranking)
nameList = []
idList = []
soldList = []
employee()```
--------
Any help would be very much so appreciated.
You could consider breaking up your logic into multiple functions and sorting a zip of the names, and num_houses_sold list to print a ranking as you specified:
def get_int_input(prompt: str) -> int:
num = -1
while True:
try:
num = int(input(prompt))
break
except ValueError:
print('Error: Enter an integer, try again...')
return num
def get_yes_no_input(prompt: str) -> bool:
allowed_responses = {'y', 'yes', 'n', 'no'}
user_input = input(prompt).lower()
while user_input not in allowed_responses:
user_input = input(prompt).lower()
return user_input[0] == 'y'
def get_single_employee_info(names: list[str], ids: list[int],
num_sold_houses: list[int]) -> None:
names.append(input('What is the employee\'s name?: '))
ids.append(get_int_input('What is the employee\'s id?: '))
num_sold_houses.append(
get_int_input('How many houses did the employee sell?: '))
def get_houses_sold_info(names: list[str], ids: list[int],
num_sold_houses: list[int]) -> None:
get_single_employee_info(names, ids, num_sold_houses)
add_another_employee = get_yes_no_input('Add another employee [yes/no]?: ')
while add_another_employee:
get_single_employee_info(names, ids, num_sold_houses)
add_another_employee = get_yes_no_input(
'Add another employee [yes/no]?: ')
def print_entered_info(names: list[str], ids: list[int],
num_sold_houses: list[int]) -> None:
print()
row_width = 12
comission_per_house = 500
header = ['Name', 'Id', 'Houses Sold', 'Commission']
print(' '.join(f'{h:<{row_width}}' for h in header))
commission = [n * comission_per_house for n in num_sold_houses]
for values in zip(*[names, ids, num_sold_houses, commission]):
print(' '.join(f'{v:<{row_width}}' for v in values))
print()
total_commission = sum(commission)
print(f'Total Commission: {total_commission}')
print()
rankings = sorted(zip(num_sold_houses, names), reverse=True)
print('Ranking:')
for houses_sold, name in rankings:
print(f'{name} - {houses_sold}')
def main() -> None:
print('Houses Sold Tracker')
print('===================')
names, ids, num_houses_sold = [], [], []
get_houses_sold_info(names, ids, num_houses_sold)
print_entered_info(names, ids, num_houses_sold)
if __name__ == '__main__':
main()
Example Usage:
Houses Sold Tracker
===================
What is the employee's name?: Laura
What is the employee's id?: 1
How many houses did the employee sell?: a
Error: Enter an integer, try again...
How many houses did the employee sell?: 4
Add another employee [yes/no]?: yes
What is the employee's name?: John
What is the employee's id?: 2
How many houses did the employee sell?: 5
Add another employee [yes/no]?: y
What is the employee's name?: BOJO
What is the employee's id?: 3
How many houses did the employee sell?: 1
Add another employee [yes/no]?: no
Name Id Houses Sold Commission
Laura 1 4 2000
John 2 5 2500
BOJO 3 1 500
Total Commission: 5000
Ranking:
John - 5
Laura - 4
BOJO - 1
As an aside if you ever make something real don't use a sequential user id, the amount of information you can obtain from just monitoring this is insane, e.g., the rate of user acquisition, which you don't want external people to be able to figure out.
You can use zip function to merge lists and then custom key sorting.
SortByName function returning the sort key name and SortBySalary function returning key salary
def SortByName(FullList):
return FullList[0]
def SortBySalary(FullList):
return FullList[2]
NamesList=['John','Laura','Bojo']
IdList=[1,2,5]
SalaryList=[2000,1000,5000]
ZippedList=zip(NamesList,IdList,SalaryList)
print ZippedList
# result
#[('John', 1, 2000), ('Laura', 2, 1000), ('Bojo', 5, 5000)]
ZippedList.sort(key=SortByName,reverse=True)
print ZippedList
# result
# [('Laura', 2, 1000), ('John', 1, 2000), ('Bojo', 5, 5000)]
ZippedList.sort(key=SortBySalary,reverse=True)
print ZippedList
# result
# [('Bojo', 5, 5000), ('John', 1, 2000), ('Laura', 2, 1000)]
If you later want to sort the lists by id, just implement id sorting function.
def SortByID(FullList):
return FullList[1]
ZippedList.sort(key=SortByID)
I am working with an external file which has data in the form of:
-12345 CSEE 35000 Bart Simpson
-12346 CSEE 25000 Harry Potter
-12350 Economics 30000 Krusty The Clown
-13123 Economics 55000 David Cameron
With the first item being the ID, the second the subject, the third the salary, and the rest being the name of the person.
In part of my program I am trying to print the information of the people who have salaries between values submitted by the user. I have put all the data in a list called lecturers then I put all the salaries in a separate list called lecturers salary and tried to make them integers because at first I thought the reason the for loop wasn't working was because when trying to access them from the lectures loop I thought they might still be part of a string at this point.
I have already used a loop in my program to print all the people who teach a specific subject. This subject is submitted by the user. I tried to use a for loop again for the salaries but its not working.
print""
# To God be the Glory
lecturer = []
lecturer_salary = []
x = 0
a = " "
print ""
String = raw_input("Please enter the lecturers details: ")
print ""
def printFormat(String):
String = String.split()
lastname = String[-1]
firstnames = " ".join(String[3:-1])
name = ", ".join([lastname, firstnames])
ID_Subject = " ".join(String[0:2])
money = String[2]
print "%s,%s %s %s" % (lastname,firstnames,ID_Subject,money)
printFormat(String)
while x < len(lecturer):
lecturer_salary.append(int(lecturer [x][2]))
x = x + 1
print ""
try:
fname = input("Enter filename within " ": ")
with open(fname) as f:
for line in f:
data = line.split()
printFormat(line)
line = line.split()
lecturer.append(line)
except IOError as e :
print("Problem opening file")
print ""
print ""
answer = raw_input("Would you like to display the details of lectureers from a particular department please enter YES or NO: ")
if answer == "YES" :
print ""
department = raw_input("Please enter the department: ")
print ""
while x < len(lecturer) :
for line in lecturer:
if lecturer[x][1] == department:
a = lecturer[x]
a = ' '.join(a)
printFormat(a)
x = x + 1
**elif answer == "NO" :
print ""
answer2 = raw_input ("Would you like to know all the lecturers within a particular salary range: ")
print ""
if answer2 == "YES":
lower_bound = int(input("Please enter the lower bound of the salary range: "))
upper_bound = int(input("Please enter the upper bound of the salary range: "))
print ""
while x < len(lecturer) :
for line in lecturer_salary:
if lower_bound < lecturer_salary[x] < upper_bound :
print lecturer_salary[x]
x = x + 1**
else:
print ""
print "Please enter a valid input"
So, you have an array of lecturer and one of lecturer salary. the
for line in lecturer_salary:
is not needed - just the while followed by the if. Note that this will only print out the salary, not the lecturer details. Since x is the index to both arrays you can access lecturer[x] for the rest. In truth you don't need the lecturer_salary at all, just walk through lecturer and check:
while x < len(lecturer) :
if lower_bound < lecturer[x][2] < upper_bound :
a = lecturer[x]
a = ' '.join(a)
printFormat(a)
x = x + 1
For starters, you shouldn't name your variable with a capital letter like String or Id_Subject.
It is simpler to break code into functions and try using a dictionary or class to improve readability and extensibility.
Here is a minimal code using class:
lecturers = [] # To store Lecturer instances, which isn't necessary
class Lecturer():
def __init__(self, id, subject, salary, name):
self.id = id
self.subject = subject
self.salary = salary
self.name = name
def readfile(filename):
"""read each line in a file and yield a list of fields"""
with open(filename, "r") as f:
for line in f.readlines():
# return a list of fields
yield line.replace("\n", "").split()
def new_lecturer(detail):
"""Return a new lecturer instance from a list of fields"""
return Lecturer(detail[0],
detail[1],
detail[2],
{"firstname": detail[3],
"lastname": detail[4]
})
def print_lecturer_detail(lecturer):
"""Accept a lecturer instance and print out information"""
print "{0},{1} {2} {3}".format(lecturer.name["lastname"],
lecturer.name["firstname"],
lecturer.id,
lecturer.salary)
def main():
"""This is where all the main user interaction should be"""
fname = raw_input("Enter filename: ")
for lecturer in (readfile(fname)):
lecturers.append(new_lecturer(lecturer))
print ""
answer = raw_input("Would you like to display lecturers by department(Y/N)?: ")
if answer == "Y":
print ""
department = raw_input("Please enter the department: ")
print ""
for lecturer in lecturers:
if lecturer.subject == department:
print_lecturer_detail(lecturer)
elif answer == "N":
# implement salary code here
pass
if __name__ == '__main__':
main()
This may be an overkill now, but it's better than dealing with lists in a long run. You'll see that dealing with properties become much simpler. You may want to improve each function further and make it more modular and reusable.
#Paul Morrington has the straight answer on the while part.
I have a txt file with the general form:
Last Name
First Name
Year
Medal (This line only contains one number either 1,2,3 meaning gold,silver,bronze respectively)
What I'm trying to do is have the user input a year and count how many medals were won for that year. then have another function where the user can input a first and last name, the function should print out "john smith won a gold(1) medal in 1864"
def medals(medalcount):
year= str(input("Please enter a year: "))
with open("textfile") as f:
medalcount+=f.read().count(year)
return medalcount
Basically I'm using this function to count how many times the string year entered by the user appears in the txt file.
As for the next part I'm still kind of confused on how to actually approach it.
Example:
Smith
John
1896
1
>>> Please enter year: 1896
15 medals won in this year
def readFile(infilepath):
answer = {}
with open(infilepath) as infile:
for lastname in infile:
lastname = lastname.strip()
firstname = infile.readline().strip()
year = infile.readline().strip()
medal = infile.readline().strip()
if year not in answer:
answer[year] = {}
if lastname not in answer[year]:
answer[year][lastname] = {}
if firstname not in answer[year][lastname]:
answer[year][lastname][firstname] = {}
if medal not in answer[year][lastname][firstname]:
answer[year][lastname][firstname][medal] = 0
answer[year][lastname][firstname][medal] += 1
return answer
def count(medalcounts):
year = input("What year would you like to check: ").strip()
answer = 0
for lastname in medalcounts[year]:
for firstname,medals in medalcounts[year][lastname].items():
answer += sum(medals.values())
print(answer, "medals were awarded in", year)
firstname = input("Enter first name: ").strip()
lastname = input("Enter last name: ").strip()
for year,yeard in medalcounts.items():
medals = yeard[lastname][firstname]
for med,count in medals.items():
print("In year", year, firstname, lastname, "won", count, '. gold silver bronze'.split()[med], "medals")
USAGE:
count(readFile('path/to/file'))
I'm trying to do a question out of my book and it asks:
Implement function names that takes no input and repeatedly asks the
user to enter a student's first name. When the user enters a blank
string, the function should print for every name, the number of
students with that name.
Example usage:
Usage:
names()
Enter next name: Valerie
Enter next name: Bob
Enter next name: Valerie
Enter next name: John
Enter next name: Amelia
Enter next name: Bob
Enter next name:
There is 1 student named Amelia
There are 2 students named Bob
There is 1 student named John
There are 2 students named Valerie
So far I have this code:
def names():
names = []
namecount = {a:name.count(a) for a in names}
while input != (''):
name = input('Enter next name: ')
names = name
if input == ('')
for x in names.split():
print ('There is', x ,'named', names[x])
I'm really lost here and any input would help out tons. Also if possible please explain how to fix my code
There are a lot of issues with namings in your function, you are using such variables like 'names' that is used for function name as well as 'input' that is a python function name for reading user input - so you have to avoid using this. Also you defining a namecount variable as a dict and trying to initialize it before fill. So try to check solution below:
def myFunc():
names = []
name = ''
while True: #bad stuff you can think on your own condition
name = raw_input('press space(or Q) to exit or enter next name: ')
if name.strip() in ('', 'q', 'Q'):
for x in set(names):
print '{0} is mentioned {1} times'.format(x, names.count(x))
break
else:
names.append(name)
myFunc()
OR:
from collections import defaultdict
def myFunc():
names = defaultdict(int)
name = ''
while True: #bad stuff you can think on your own condition
name = raw_input('press space(or Q) to exit or enter next name: ')
if name.strip() in ('', 'q', 'Q'):
for x in set(names):
print '{0} is mentioned {1} times'.format(x, names[x])
break
else:
names[name] += 1
I rewrote your function for you:
def names():
names = {} # Creates an empty dictionary called names
name = 'cabbage' # Creates a variable, name, so when we do our while loop,
# it won't immediately break
# It can be anything really. I just like to use cabbage
while name != '': # While name is not an empty string
name = input('Enter a name! ') # We get an input
if name in names: # Checks to see if the name is already in the dictionary
names[name] += 1 # Adds one to the value
else: # Otherwise
names[name] = 1 # We add a new key/value to the dictionary
del names[''] # Deleted the key '' from the dictionary
for i in names: # For every key in the dictionary
if names[i] > 1: # Checks to see if the value is greater for 1. Just for the grammar :D
print("There are", names[i], "students named", i) # Prints your expected output
else: # This runs if the value is 1
print("There is", names[i], "student named", i) # Prints your expected output
When doing names():
Enter a name! bob
Enter a name! bill
Enter a name! ben
Enter a name! bob
Enter a name! bill
Enter a name! bob
Enter a name!
There are 3 students named bob
There are 2 students named bill
There is 1 student named ben
Let's analyse your code:
def names():
names = []
namecount = {a:name.count(a) for a in names}
while input != (''):
name = input('Enter next name: ')
names = name
if input == ('')
for x in names.split():
print ('There is', x ,'named', names[x])
There seem to be a few problems, let's list them
The while loop's conditional
What you want to do check if input from user is '' (nothing)..
input is a built-in function for getting input from user, so it never will be ('').
The names = name statement
What you want to do is add name to the list names.
Here you are changing names to a string, which isn't what you want.
The if's conditional
same as 1.
The for loop
let's ignore.. just not valid.. here..
We fix these problems as follows(solution has same numbering as problem above that it solves)
Change the conditional to something like name != ''.
Also, before the loop begins, you need to get input once for this to work, which in this case has a bonus, the first input can have a different prompt.
Use names.append(name) to add name to names.
Same as 1.
Just look at the for loop below...
Try this
def names():
names = []
name = input('Enter a name: ').strip() # get first name
while name != '':
names.append(name)
name = raw_input('Enter next name: ').strip() # get next name
for n in set(names): # in a set, no values are repeated
print '%s is mentioned %s times' % (n, names.count(n)) # print output
def names():
counters = {}
while True:
name = input('Enter next name:')
if name == ' ':
break
if name in counters:
counters[name] += 1
else:
counters[name] = 1
for name in counters:
if counters[name] == 1:
print('There is {} student named {}'.format(counters[name],name))
else:
print('There are {} student named {}'.format(counters[name],name))
names()