Auto append list items in dictionary with default values python - python

I am trying to create an attendance logger where I create a dictionary which I fill with student names. The names will be lists where I append their class attendance data (whether they attended class or not). The code I have so far is displayed below`
#! /bin/python3
#add student to dict
def add_student(_dict):
student=input('Add student :')
_dict[student]=[]
return _dict
#collect outcomes
def collector(student,_dict, outcome):
_dict[student].append(outcome)
return _dict
#counts target
def count(_dict,target):
for i in _dict:
# records total attendance names
attendance_stat = len(_dict[i])
# records total instances absent
freq_of_absence=_dict[i].count(target)
# records percentage of absence
perc_absence = float((freq_of_absence/attendance_stat)*100)
print(i,'DAYS ABSENT =',freq_of_absence)
print('TOTAL DAYS: ', i, attendance_stat)
print('PERCENTAGE OF ABSENCE:', i, str(round(perc_absence, 2))+'%')
#main function
def main():
#date=input('DATE: ')
outcomes=['Y','N']
student_names = {}
try:
totalstudents = int(input('NO. OF STUDENTS: '))
except ValueError:
print('input an integer')
totalstudents = int(input('NO. OF STUDENTS: '))
while len(student_names) < totalstudents:
add_student(student_names)
print(student_names)
i = 0
while i < totalstudents:
i = i + 1
target='Y'
student=str(input('student :'))
outcome=str(input('outcome :'))
collector(student,student_names,outcome)
count(student_names,target)
if __name__=='__main__':
main()
`
The code works well so far but the problem is when the number of students is too large, time taken to input is extensive cutting in on class time. Since the number of absentees is usually less than those present, is it possible to select from the dictionary students absent which will append the value Y for each selected absent, while appending N to the remaining lists in dictionary.

This isn't exactly what you're asking for, but I think it will help. Instead of asking the user to input a name each time for the second part, why not just print the name yourself, and only ask for the outcome? Your last while loop would then become a for loop instead, like this:
for student_name in student_names:
outcome = input("Outcome for {}: ".format(sudent_name))
collector(student_name, student_names, outcome)
You could also add some logic to check if outcome is an empty string, and if so, set it to 'N'. This would just allow you to hit enter for most of the names, and only have to type in 'Y' for the certain ones that are absent. That would look like this:
for student_name in student_names:
outcome = input("Outcome for {}: ".format(sudent_name))
if outcome = "":
outcome = "N"
collector(student_name, student_names, outcome)

Related

Dictionary not updating if key and value are not unique

Im new to python and Im creating this gambling game where a user will have the choice to bet on symbols that will be generated (eventually- haven't gotten there yet). Im creating a dictionary to hold my data for how much the user is betting (the value) and the number corresponding to the symbol they are betting on (the key). Each player has the option to place more than 1 bet per turn. I am running into a problem where if two different players input the same bet&symbol combination (for example $10 on 1 (Crown)) then the dictionary wont update to contain 2 separate entries of 1:10, it will only have one entry of 1:10. This is what Im working with right now
def getPlayers():
print("Hello and Welcome to the Crown and Anchor Game")
num = int(input('Please enter the number of people playing today: ')) # takes the number of people who are playing from the user
scoreInit = [] # creating an empty list for the players inital score of 10
for i in range(num): # for loop to append the inital score of 10 to the empty list scoerInit for the amount of players input
scoreInit += i * [10]
return scoreInit # returns the list of inital scores for the amount of players playing
def collectBets(balance):
bets = {}
index = 0
for i in balance:
index += 1
print('Player %d, what would you like to do this round?' % (index))
print('1: Bet on a symbol')
print('2: Skip this round')
userOpt = int(input('Please enter 1 or 2 depending on your choice: ')) # assigning what the user inputs as the variable 'usesrOpt'
if userOpt == 1: # if user decides to bet:
betTimes = int(input('How many times would you like to bet this round?: '))
for a in range(betTimes):
betAmount = int(input('Enter the amount you would like to bet this round: $1, $2, $5, or $10: '))
symbol = int(input('Enter the number corresponding to the symbol you would like to bet on\n' # asking user what symbol they want to bet on - assigning it to a variable
'1: Crown\n'
'2: Anchor\n'
'3: Heart\n'
'4: Diamond\n'
'5: Club\n'
'6: Spade\n'
))
bets.update({symbol:betAmount})
print(bets)
def main():
balance1 = getPlayers()
collectBets(balance1)
main()
Any help would be much appreciated! Thank you!
It is best to think of a Python Dictionary as "an un ordered set of key: value pairs, with the requirement that the keys are unique (within one dictionary)." https://docs.python.org/3/tutorial/datastructures.html
With that being said, whenever user A chooses 10, and then user B chooses 10; user A choice is literally being overwritten by user B's choice. A single dictionary can only hold 10 once as a key. In order to resolve your solution you'll have to use some other data structures. The key within a dictionary should be unique.
A solution to your problem could be to use different levels of dictionaries. You could have a dictionary of player names that holds a dictionary of their value, and their symbol. However, your player names would have to be unique, otherwise you would run into the same issue.

Python: How to get data from other defined function to the other?

I have this program:
def NoOfPeople(people):
if people.isdigit() and (int(people)>=1) and (int(people)<=1000):
return True
else:
print('invalid')
while True:
people = input('No. of people:')
if NoOfPeople(people):
break
How do I use data from it to a new defined function as I have this menu and program which I am stuck at right now on how to continue to get the data from the previous one.It is to check if the selected room can accommodate to the number of people that are entered in NoOfPeople(people). So how can I compare the number of people with which room it can accommodate:
Room
[1] Room A (10 person)
[2] Room B (30 person)
[3] Room C (50 person)
venue = input('Please select a venue:')
def validateVenue(venue):
if venueList == '1':
(what should I continue from here?)
Help and suggestion please as I am new in using python.Thanks
This is pretty open ended but I will try and help you out.
in general you can pass a variable / data_structure to another function and return it out of the function back to whatever called the function like this...
def function_name(var1, var2):
var3 = var1*var2
return var3
new_var = function_name(3, 5)
print(new_var)
output
15
1) I don't know what venuList looks like you might want to make a Key value pair (dictionary)
def select_venue(num_of_people):
#this is your venue key value dictionary, IE your available venues and their size
venues = {10:"Venue Small Conf Room" , 30:"Venue Ballroom", 50:"Venue Large Conf Room", 3:"Venue Office"}
venue_options = []
for occupancy in venues:
if occupancy >= num_of_people:
venue_options.append(occupancy)
venue = min(venue_options)
venue_name = venues[venue]
print("Please Use {} for your event with {} people (max occupancy {})".format(venue_name,num_of_people, venue))
if __name__ == "__main__":
people = 4 #change this value to test
select_venue(people)
your output should look like this
Please Use Venue Small Conf Room for your event with 4 people (max
occupancy 10)
You will notice the key is the max occupancy of a venue and the value is the name of the venue.
You should also take note they don't have to be in order (small office is last)

Making a statistics program

I am trying to write a Python program that computes and prints the following :
the average score from a list of scores
the highest score from a list of scores
the name of the student who got the highest score.
The program starts by asking the user to enter the number of cases. For EACH case, the program should ask the user to enter the number of students. For each student the program asks the user to enter the student's name and marks. For EACH case the program reports the average marks, the highest marks and the name of the student who got the highest marks.
Also
If there are more than one person with the highest score in a CASE, the program should report the first occurrence only.
The average score and the highest score should have exactly 2 decimal places.
The output should be as in the sample program output.
What I have been trying so far is the following:
grade=[]
name_list=[]
cases=int(input('Enter number of cases: '))
for case in range(1,cases+1):
print('case',case)
number=int(input('Enter number of students: '))
for number in range (1,number+1):
name=str(input('Enter name of student: '))
name_list.append(name)
mark=float(input('Enter mark of student:'))
grade.append(mark)
highest= max (grade)
average=(sum(grade)/number)
high_name=grade.index(max(grade))
print('average',average)
print('Highest',highest)
print (high_name)
This is what i have deciphered so far. my biggest problem now is getting the name of the individual with the high score. Any thoughts and feedback is much appreciated. As with respect to the answer posted below, i am afraid the only thing i do not understand is the dictionary function but otherwise the rest does make sense to me.
This resembles an assignment, it is too specific on details.
Anyways, the official docs are a great place to get started learning Python.
They are quite legible and there's a whole bunch of helpful information, e.g.
range(start, end): If the start argument is omitted, it defaults to0
The section about lists should give you a head start.
numcases = int(input("How many cases are there? "))
cases = list()
for _ in range(numcases):
# the _ is used to signify we don't care about the number we're on
# and range(3) == [0,1,2] so we'll get the same number of items we put in
case = dict() # instantiate a dict
for _ in range(int(input("How many students in this case? "))):
# same as we did before, but skipping one step
name = input("Student name: ")
score = input("Student score: ")
case[name] = score # tie the score to the name
# at this point in execution, all data for this case should be
# saved as keys in the dictionary `case`, so...
cases.append(case) # we tack that into our list of cases!
# once we get here, we've done that for EVERY case, so now `cases` is
# a list of every case we have.
for case in cases:
max_score = 0
max_score_student = None # we WILL need this later
total_score = 0 # we don't actually need this, but it's easier to explain
num_entries = 0 # we don't actually need this, but it's easier to explain
for student in case:
score = case[student]
if score > max_score:
max_score = score
max_score_student = student
total_score += score
num_entries += 1
# again, we don't need these, but it helps to demonstrate!!
# when we leave this for loop, we'll know the max score and its student
# we'll also have the total saved in `total_score` and the length in `num_entries`
# so now we need to do.....
average = total_score/max_entries
# then to print we use string formatting
print("The highest score was {max_score} recorded by {max_score_student}".format(
max_score=max_score, max_score_student=max_score_student))
print("The average score is: {average}".format(average=average))

Trying to calculate highest marks with name in python

grade=[]
names=[]
highest=0
cases=int(input('Enter number of cases: '))
for case in range(1,cases+1):
print('case',case)
number=int(input('Enter number of students: '))
for numbers in range (1,number+1):
name=str(input('Enter name of student: '))
names.append(name)
mark=float(input('Enter mark of student:'))
grade.append(mark)
print('Case',case,'result')
print('name',list[list.index(max(grade))])
average=(sum(grade)/number)
print('average',average)
print('highest',max(grade))
print('name',names[grade.index(max(grade))])
I want to print name of the student with the highest mark. I have not learned anything other than list, while and for. NO dictionary ..nothing. I was wondering how can i do this?
ALSO i am getting this error!!! builtins.AttributeError: 'str' object has no attribute 'append'. HELP. thank you! :D
for number in range (1,number+1):
Don't reuse variable names for different things, call one of them numbers and the other number:
numbers=int(input('Enter number of students: '))
for number in range (1,numbers+1):
You made name a list in the beginning:
name=[]
but here you assign a single input to it:
name=str(input('Enter name of student: '))
The you append the new name to itself:
name.append(name)
which is not possible, because name is after the input no longer a list but a string. Again using different variable names for different things would help. Call the array names and the single input name:
names = []
#...
name=str(input('Enter name of student: '))
names.append(name)
And here:
print('name',list[list.index(max(grade))])
list is a build-in type, not one of your variables, so what you are trying to do is index a type, not a specific list. If you want to call index on a specific list you do so by using the variable name of that list. grade.index(...) will find the specific position matching the passed grade in grade and then you can use this position to get the corresponding name, because you know, that the name is at the same position in names:
print('name',names[grade.index(max(grade))])
Here is a somewhat more elaborated version; working through it should give you a better feel for the language.
from collections import namedtuple
import sys
# Python 2/3 compatibility shim
if sys.hexversion < 0x3000000:
inp, rng = raw_input, xrange # Python 2.x
else:
inp, rng = input, range # Python 3.x
def type_getter(type):
"""
Build a function to prompt for input of required type
"""
def fn(prompt):
while True:
try:
return type(inp(prompt))
except ValueError:
pass # couldn't parse as the desired type - try again
fn.__doc__ = "\n Prompt for input and return as {}.\n".format(type.__name__)
return fn
get_int = type_getter(int)
get_float = type_getter(float)
# Student record datatype
Student = namedtuple('Student', ['name', 'mark'])
def get_students():
"""
Prompt for student names and marks;
return as list of Student
"""
students = []
while True:
name = inp("Enter name (or nothing to quit): ").strip()
if name:
mark = get_float("Enter {}'s mark: ".format(name))
students.append(Student(name, mark))
else:
return students
def main():
cases = get_int("How many cases are there? ")
for case in rng(1, cases+1):
print("\nCase {}:".format(case))
# get student data
students = get_students()
# perform calculations
avg = sum((student.mark for student in students), 0.) / len(students)
best_student = max(students, key=lambda x: x.mark)
# report the results
print(
"\nCase {} average was {:0.1f}%"
"\nBest student was {} with {:0.1f}%"
.format(case, avg, best_student.name, best_student.mark)
)
if __name__=="__main__":
main()
which runs like:
How many cases are there? 1
Case 1:
Enter name (or nothing to quit): A
Enter A's mark: 10.
Enter name (or nothing to quit): B
Enter B's mark: 20.
Enter name (or nothing to quit):
Case 1 average was 15.0%
Best student was B with 20.0%

How to call in a specifc csv field value in python

I am so new to python (a week in) so I hope I ask this question properly.
I have imported a grade sheet in csv format into python 2.7. The first column is the name of the student and the column titles are the name of the assignments. So the data looks something like this:
Name Test1 Test2 Test3
Robin 89 78 100
...
Rick 72 100 98
I want to be able to do (or have someone else do) 3 things just by typing in the name of the person and the assignment.
1. Get the score for that person for that assignment
2. Get the average score for that assignment
3. Get that persons average score
But for some reason I get lost at figuring how to get python to recognize the field I am trying to call in. So far this is what I have (so far the only part that works is calling in file):
data = csv.DictReader(open("C:\file.csv"))
for row in data:
print row
def grade()
student= input ("Enter a student name: ")
assignment= input("Enter a assignment: ")
for row in data:
task_grade= data.get(int(row["student"], int(row["assignment"])) # specific grade
task_total= sum(int(row['assignment'])) #assignment total
student_total= #student assignments total-- no clue how to do this
task_average= task_total/11
average_score= student_total/9
You can access the individual "columns" of your csv this way:
import csv
def parse_csv():
csv_file = open('data.csv', 'r')
r = csv.reader(csv_file)
grade_averages = {}
for row in r:
if row[0].startswith('Name'):
continue
#print "Student: ", row[0]
grades = []
for column in row[1:]:
#print "Grade: ", column
grades.append(int(column.strip()))
grade_total = 0
for i in grades:
grade_total += i
grade_averages[row[0]] = grade_total / len(grades)
#print "grade_averages: ", grade_averages
return grade_averages
def get_grade(student_name):
grade_averages = parse_csv()
return grade_averages[student_name]
print "Rick: ", get_grade('Rick')
print "Robin: ", get_grade('Robin')
What you are trying to do is not meant for Python because you have keys and values. However...
If you know that your columns are always the same, no need to use keywords, you can use positions:
Here is the easy, inefficient* way to do 1 and 3:
students_name = ...
number = ...
for line in open("C:\file.csv")).readlines()
items = line.split()
num_assignments = len(items)-1
name = items[0]
if name = students_name:
print("assignment score: {0}".format(items[number]))
asum = 0
for k in range(0,num_assignments):
asum+= items[k+1]
print("their average: {0}".format(asum / num_assignments)
To do 2, you should precompute the averages and return them beucase the averages for each assignment is the same for each user query.
I say easy *innefficnet because you search the text file for each user query each time a name is entered. To do it properly, you should probably build a dictionary of all names and their information. But that solution is more complicated, and you are only a week in! Moreover, its longer and you should give it a try. Look up dict.
I believe the reason you are not seeing the field the second time around is because the iterator returned by csv.DictReader() is a one-time iterator. That is to say, once you've reached the last row of the csv file, it will not reset to the first position.
So, by doing this:
data = csv.DictReader(open("C:\file.csv"))
for row in data:
print row
You are running it out. Try commenting those lines and see if that helps.

Categories

Resources