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'))
Related
My code below works as long as all of the student's name consists of only two names - ex. Julie Andrews. But, when generating the student's emails, I'm trying to account for the students who have two first names - ex. Mary Jane Stewart. I want it to output something like MJStewart123#gmail.org, vs. what my current code will print, which is MJane123#gmail.com - totally ignoring the student's last name.
After hours of researching Google, I have tried updating my create_emails fx to change my original variable first_last = name.split(" ") to something like first, middle, last = name.split(" ") or first_last = name.split(" ", 2) while also, respectively, updating the line utilizing the attribute .append from its original to student_emails.append(first_last[0][0] + first_last1 + first_last[2]+ last_three_sid + "#gmail.com") or student_emails.append(first[0] + middle[0] + last + last_three_sid + "#gmail.com"). All attempts have obviously returned some form of an error...
The attached Stack Overflow article is the closest thing I could find whose logic might be applicable to what I'm trying to accomplish here, specifically the comment by Manfred, but in reading it, I don't know how to apply what they've done to my program... because I don't quite understand what it is that I'm reading... since I'm such a newbie at all this. I'd appreciate any help you can offer.
student_names = []
def create_names():
count = 1
while count <= 5:
name = input("Enter student name, please. ")
student_names.append(name)
count += 1
create_names()
import random
student_ids = []
def create_ids():
student_id = random.randint(111111,999999)
return student_id
def create_id_list():
for name in student_names:
student_ids.append(create_ids())
create_id_list()
student_emails = []
def create_emails():
for name in student_names:
first_last = name.split(" ")
sid = str(student_ids[student_names.index(name)])
len_sid = len(sid)
last_three_sid = sid[len_sid-3:len_sid]
student_emails.append(first_last[0][0] + first_last[1] + last_three_sid + "#gmail.com") #ignores last index if one is provided.
create_emails()
def student_info():
for name in student_names:
name_pos = student_names.index(name)
print("\n" + "name: " + name)
print("id: " + str(student_ids[name_pos]))
print("email: " + student_emails[name_pos])
student_info()
Finding and first and middle initials in a list of names in python
You could do it like this I guess:
student_names = []
def create_names():
count = 1
while count <= 5:
name = input("Enter student name, please. ")
student_names.append(name)
count += 1
create_names()
import random
student_ids = []
def create_ids():
student_id = random.randint(111111,999999)
return student_id
def create_id_list():
for name in student_names:
student_ids.append(create_ids())
create_id_list()
student_emails = []
def create_emails():
for name in student_names:
email_name = ""
first_last = name.split(" ")
for i, v in enumerate(first_last):
if i > len(first_last)-2:
break
email_name+=v[0]
email_name = email_name+first_last[-1]
sid = str(student_ids[student_names.index(name)])
len_sid = len(sid)
last_three_sid = sid[len_sid-3:len_sid]
student_emails.append(email_name + last_three_sid + "#gmail.com") #ignores last index if one is provided.
create_emails()
def student_info():
for name in student_names:
name_pos = student_names.index(name)
print("\n" + "name: " + name)
print("id: " + str(student_ids[name_pos]))
print("email: " + student_emails[name_pos])
student_info()
Result:
Enter student name, please. Julie Andrews
Enter student name, please. Mary Jane Stewart
Enter student name, please. Jack Hendricks
Enter student name, please. Maria Basset Juliett
Enter student name, please. Marco Hansen
name: Julie Andrews
id: 742536
email: JAndrews536#gmail.com
name: Mary Jane Stewart
id: 823274
email: MJStewart274#gmail.com
name: Jack Hendricks
id: 590875
email: JHendricks875#gmail.com
name: Maria Basset Juliett
id: 982168
email: MBJuliett168#gmail.com
name: Marco Hansen
id: 671240
email: MHansen240#gmail.com
The code is too redundant and could be implemented with some simpler structures.
name construction can use split combined with join function
storage can also use dictionaries to store multiple information about the same object, compared to multiple lists so more concise and efficient
The code itself is not a big problem, mainly the syntax structure requires more skilled,let's encourage each other in our endeavours
try this:
import random
info = []
# You can use for loop if you already know how many times it will loop
for i in range(5):
name = input("Enter student name, please:") # get name
student_id = random.randint(111111, 999999) # get id
name_structure = name.split()
email = "{name_abbr}{last_name}{sid}#gmail.com".format(
name_abbr="".join([item[0] for item in name_structure[:-1]]), # Generate initials
last_name=name_structure[-1], # Generate the last part of the name
sid=str(student_id)[-3:] # Generate the id in the mailbox
)
info.append({"name": name, "id": student_id, "email": email}) # Store to the list, or print directly
# Print Information
for item in info:
print("name:", item["name"])
print("id:", item["id"])
print("email:", item["email"])
print()
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)
My input needs to be for example
name surname, street name 22b, 10000 Zagreb
and it need to output like this:
name and surname: name surname
Street: street name
street number: 22
house number: b
postal code: 100000
place: zagreb
and this is my code
whole_string =input("Person: ")
string_list = whole_string.split(", ")
split_street_and_street_number = string_list[1].split(" ")
postal_code_and_city = string_list[2].split(" ")
print(f"name and surname: {string_list[0]}")
print(f"street: {split_street_and_street_number[0]}")
print(f"street number: {split_street_and_street_number[1]}")
print(f"postal code: {postal_code_and_city[0]}")
print(f"city: {postal_code_and_city[1]}")
Please check out this.
import re
text = '22b'
street_number =" ".join(re.findall("[0-9]+", text))
house_number =" ".join(re.findall("[a-zA-Z]+", text))
print(street_number)
print(house_number)
You can find the index of the first letter and split the string using that index:
def find_index_of_first_letter(text):
for index, value in enumerate(text):
try:
int(value)
except ValueError:
return index
print('No letter in the text')
text = '22b'
first_letter = find_index_of_first_letter(text)
number, letters = text[:first_letter], text[first_letter:]
I need to define a search function for my code that searches for letters within my dictionary. I am only missing the actual 'search' loop and code. Many lines of code have been left out for ease of reading.
while True:
option = get_option()
...
elif (option == "S"):
search(users)
...
users = {}
def add(users):
student_number = input('Enter student number: ')
family_name = input("Enter family name: ")
first_name = input("Enter first name: ")
phone_number = input('Enter phone number: ')
single_info = {"student_number": student_number, "family_name": family_name, "first_name": first_name, "phone_number": phone_number}
users[student_number] = single_info
print("Record is added.")
...
family_name = input("Enter family name: ")
first_name = input("Enter first name: ")
# STN Name Phone
1 0123456 John Smith 111222
2 1111111 Mary Lee 001122
3 2222222 Hoa Zhang 334455
2 7676767 Milka Sjanovic 012012
This is the dictionary with the inputs, I require a search function to search for names within this.
expected output is
Search record by name.
Enter text to search: Mi
Search found 2 records.
# STN Name Phone
1 0123456 John Smith 111222
2 7676767 Milka Sjanovic 012012
You can traverse your dictionary using a comprehension to build a result set:
text = input("Enter text to search:").lower()
result = [ s for s in users.values() if text in (s["family_name"]+" "+s["first_name"]).lower() ]
print(f"Search found {len(result)} records")
for i,s in enumerate(result):
print(i+1,s["student_number"],s["first_name"],s["family_name"],s["phone_number"])
note: Given that you provided no usable test data, I just typed this in the answer box. You will need to fix any typos, and add formatting yourself
You could also separate the criteria definition from the search process like this:
criteria = lambda s:any(text in s[n].lower() for n in ["family_name","first_name"])
result = list(filter(criteria,users.values()))
This will give you more flexibility and the ability to easily create searches on other fields. For example, searching in any field:
criteria = lambda s: text in " ".join(s.values()).lower()
result = list(filter(criteria,users.values()))
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)