Editing lists in a dictionary Python 3.7 - python

I am trying to print out a dictionary that shows a students ID, Name and Grades so it looks like this "ID:{'Name': 'Students Name', Grades[Grade1, Grade2, Grade3....]. When I am doing this and print out the dictionary it will only print our the grade for the last assignment for each student dictionary. For example if student 1 got a 30 on the last assignment and student 2 got a 40 on the last assignment. The output is:
enter code here
1:{'Name': 'Student 1', 'Grades': [30, 40]}
2:{'Name': 'Student 2', 'Grades': [30, 40]}
My original problem was everyscore for every student was in the dictionary, I thought I fixed this by emptying the Grades list in the loop after the grades go in. But now i have this problem. Im not quite sure what the problem is and Im going to try and work on it but any help would be appreciated. MY code is below.
enter code here
students = {}
grades = []
while True:
blank = {}
student_name = input("What is the student's name? ")
student_id = input("What is the student's ID number? ")
blank['Name'] = student_name
blank['Grades'] = grades
students[student_id] = blank
y_or_n = input("Would you like to enter another student? Yes or No ")
if y_or_n == "Yes":
continue
else:
break
homework_assignments = int(input("How many homework assignments were
given? "))
for i in students.keys():
print("Please enter the grades for {}".format(students[i]['Name']))
for j in range (1, homework_assignments + 1):
grade = int(input("What was the grade for homework {}?".format(j)))
grades.append(grade)
for i in students.keys():
students[i]['Grades'] = grades
grade = []
for key in students.keys():
print("{}:{}".format(key, students[key]))

When you callstudents['Grades'] = grades you are modifying the same dictionary while iterating through it's keys. The correct code should be students[i]['Grades'] = grades since you have declared the Grades as a nested structure of students above. There is another mistake, you are using the varibale i as an index to iterate through the assignments as well as the students, which results in i being incremented in an unexpected manner. Try the following snippet.
for i in students.keys():
print("Please enter the grades for {}".format(students[i]['Name']))
for j in range (1, homework_assignments + 1):
grade = int(input("What was the grade for homework {}? ".format(i)))
if grade < 0 or grade > 100:
print("Grades need to be between 0 - 100")
grades.append(grade)
students[i]['Grades'] = grades

Some things I have noticed:
Your checking of invalid grades does nothing, the grade will still be added incorrectly. To fix this, you need to make sure that the grade is not added if it is outside that range, and that you repeat that i'th iteration.
This is not really accomplish-able with a for loop in your current structure, maybe a while loop would suit it better.
I also noticed you have used the variable i for two of your loops, which means that it is getting overwritten and causing confusing things to happen.
There are a whole host of logical errors towards the bottom and I think it would help you if you printed out the students dictionary before you print it to see its structure.
From my perspective I see has keys that are the student's ID numbers, with corresponding values of their name and this grades list. It also has a key that is 'Grades' which holds the same grades list.
The reason you are seeing all of the grades is because of a small detail about how python handles lists. The problem you are seeing is related to assignment and copying - you want to copy the contents at that point and then empty it after you are done assigning so the next student has an empty list. What you are currently doing is assigning the list which is effectively making every grade list point to the same list.
I'd personally like to stray away from literally writing the code for you, but if you have further questions just comment them and I will guide you through it.

Related

how to write a program that using lists for calculating GPA of students in python

I have to write a program in python that user inputs 3 majors and then he inputs students for each major with their classes and their scores for each class and then my program should calculate each student's GPA and then prints the best and worst student according to their GPA.
I was thinking to a program that is has 3 major lists and each list has another list inside of it for students and each student list has another two lists inside of it for classes and scores! But it seems impossible because for writing it I don't know user's inputs so I can not call the student name.
I mean if I had this list:
Math = [Jack[], Max[], Sarah[]]
I could easily use Jack[] but when I don't know users inputs so I can not write the program this way!
Any idea?
Don't know if this is late, but maybe you could work with dictionaries:
majors = {}
for i in range(3):
major = input('Insert a major\n')
majors[major] = {}
print("To terminate type 'end'\n")
for major in majors:
student = ""
while student != "end":
student = input('Insert a student for major {}\n'.format(major))
if student != "end":
majors[major][student] = {}
stud_class = ""
while stud_class != "end":
stud_class = input('Insert a class for student {}\n'.format(student))
if stud_class != "end":
grade = input('Insert grade\n')
majors[major][student][stud_class] = grade
print(majors)
# Example throwing inside some random bunch of data, just so you can get the feeling
>> {'Math': {'Laura': {'IT': '10', 'English': '8'}, 'Marco': {'Spanish': '4'}}, 'English': {'Jen': {'IT': '9'}}, 'Spanish': {}}
Of course you'll have to add validation on user input because things could easily go wrong.
Also majors are fixed in number, but the students and classes for each students aren't. A simple solution to stop the input could be: when the user enters "end" you discard that input and pass to the next thing.
Hope this helps!

Errors when trying to generate a list from input that's converted to an integer and stored in a dictionary to return a message

The first piece of code works great to make a user input dictionary. In the code below and after that I try to make a list that includes only the users whose age is under 20 years old from out of the input dictionary to return a message that references their name to say "[name] is under 20 years old."
#Make a dictionary for 5 users' input
user_info = {}
for i in range(5):
name, user_info[name] = input('Enter name: '), int(input('Enter age: '))
print(user_info)
Here's where I'm hung up. I keep getting:
TypeError: '<' not supported between instances of 'str' and 'int'
I'm trying to iterate through the list of keys and separate out the data I want from that I don't need.
#Print a message for all users under age 20
under_users = []
for user_info[name] in user_info:
if user_info[name]< 20:
under_users.append(user_info[name])
continue
else:
break
print(f"{name} is younger than 20 years old.")
I am still learning how to apply while loops. Any help much appreciated.
You need to traverse through the dictionary. Don't use the dictionary itself to traverse. Use a separate variable like i.
for i in user_info:
if user_info[i]< 20:
print(f"{i} is younger than 20 years old.")
If you need to make a list. You can still do that.
When you are traversing through a dictionary, you are accessing its key. In your case, name of the person is key itself. And when u pass that key to dictionary, you get to access the value. In your case the age is the value itself.
Note that i is the key in my code. I am using it to traverse the dictionary. And user_info[i] is the value I get after passing the key i to the dictionary user_info.
Dictionary class has an inbuilt method items(). This method produces an iterable object which can be traversed using two variables to acces both key and value at the same time.
for key, value in user_info.items():
if value < 20:
print(f"{key} is younger than 20 years old.")
If u don't like passing the key to the dictionary again & again!
There's a pythonic way of doing this:
print(*[f'{key} is younger than 20 years old' for key, value in user_info.items() if value < 20], sep='\n')
You cannot apply a string as a index in python.
When you do user_info[name] you mean "name"
Instead do dictionary..items() functions to get key and value of each index.
See what we'll do here is we'll take each pair in the dictionary into key and value variables and then used them to operate over them
user_info = {}
for i in range(0,5):
name, user_info[name] = input('Enter name: '), int(input('Enter age: '))
print(user_info)
under_users = []
for key,value in user_info.items():
if user_info[key]< 20:
under_users.append(user_info[key])
continue
else:
print(f"{key} is younger than 20 years old.")
print(under_users)
Try this
under_users = []
for name, age in list(user_info.items()):
if age < 20:
under_users.append(name)
print(f"{name} is younger than 20 years old.")
The problem with your code are the following.
for user_info[name] in user_info - If user_info = {"Anne": 25, "Bob":3}, then the first time you enter the loop, user_info[name]
becomes the first key of the dictionary, i.e. user_info[name] = 'Anne' So in the if-condition, you are comparing 'Anne' to 20.
Next is that if you break at else, the first time you encounter
someone aged >= 20, you will exit the loop without going through the
rest of the dictionary. So you do not need the else.
Lastly, the print(f"{name} is younger than 20 years old.") will
need to be nested under the if age < 20. Otherwise you will print
just the age of the last person in the dict. On that note, you do
not need the continue there because no code after the continue
will be executed for that iteration of the loop and the even without
the continue, the loop will continue as long as the condition is
true, which in this case means that as long as there are elements in
user_info.
You can't compare a string and an integer. If I ask you, which is greater, 100 or 50? You'll obviously answer 100.
But if I ask you, which is greater, "Hello World!" or 127, what will you say?
Check whether the age is less than 20, you can't check whether the name is less than 20.
#Make a dictionary for 5 users' input
infos = []
for i in range(5):
inputs = {"name": input("Name:"), "age": input("Age: ")}
infos.append(inputs)
#Print a message for all users under age 20
under_users = []
for i in infos:
if i["age"] < 20:
under_users.append(i["name"])
print("The people under 20 are:")
print(under_users)
Also, in your second loop, you ran break under the else block. So if somebody would have been more than 20, it would stop checking and other people younger than 20 would have been ignored.
Read these:
Dictionaries in Python
Break statements in Python
Python control flow tools

Add more values in a list at once in Python

I'm a beginner in Python and I'm trying to solve this problem.
I'm trying to write a code where you can put your name and the amount that you want to donate.
The thing is, deppending on the amount of the donation you can have more chances to be the winner.
Eg. If you donate $10 (1 chance), $20(2 chances), $30(3 chances).
My biggest problem is because I can't figure out how to solve this problem when the person insert $30 its name goes to the list 3 times and so on. I tried to use "for..inrange():" but without any sucess. Can someone explain me how to do this?
from random import shuffle
from random import choice
list = []
while True:
name = str(input('Write your name: '))
donation = float(input('Enter the amount you want to donate.: $ '))
list.append(name)
print('You donated $ {}. Thank you {} for you donation!'.format(donation, name))
print('=-'*25)
print('[1] YES')
print('[2] NO')
answer = int(input('Would you like to make another donation? '))
if answer == 1:
continue
else:
shuffle(list)
winner = choice(list)
break
print('The winner was: {}' .format(winner))
First do not use the name of a built-in type as a (meaningless) variable name. Change list to entry_list.
For the particular problem
compute the quantity of chances;
make a list of the person's name that many times;
extend the entry list with that list of repeated name.
Code:
entry_list = []
while ...
...
chances = int(donation) // 10
entry_list.extend( [name] * chances )
An alternative to adding another loop with additional control flow, you can use list.extend() with a list expression:
num_chances = donation // 10
chances = [name] * num_chances
all_chances.extend(chances)
Note that list is a built-in python identifier, and it's not a good idea to overwrite it. I've used all_chances instead.
Rather than adding extra names to the list to represent the higher chance, you could use the donations as weights in the random.choices function:
from random import choices
names, donations = [], []
while True:
names.append(input('Write your name: '))
donations.append(float(input('Enter the amount you want to donate.: $')))
print(f'You donated ${donations[-1]}. Thank you {names[-1]} for your donation!')
print('=-'*25)
print('[1] YES')
print('[2] NO')
if input('Would you like to make another donation? ') != '1':
break
winner = choices(names, donations)[0]
print(f'The winner was: {winner}')
This allows for non-integer donations to be counted fairly -- e.g. if Bob donates $0.25 and Fred donates $0.50, the drawing will still work in a reasonable way. It also allows very large donations to be handled without tanking the performance of the program -- if you have one list entry per dollar donated, what happens if Elon donates $20B and Jeff donates $30B? (The answer is that your fan spins really fast for a while and then the program crashes because you can't create a list with 50 billion elements -- but this is not a problem if you simply have a list of two elements with large int values.)
Note that shuffle is not necessary if you're using random.choices (or random.choice for that matter) because those functions will already make a random selection from the list.
You can use a for loop to append the name to the list more than one time :
for i in range(donation//10):
list.append(name)
This code should do the job. Please follow good naming conventions as pointed out by others. I have changed the list variable to donations as it is forbidden to use keywords as variables.
I have included the name in donations int(name) // 10 times using the extend function as pointed out by others. You may change the number of times as you wish.
from random import shuffle
from random import choice
donations = []
makeDonation = True
winner = "Unknown"
while makeDonation:
name = str(input('Write your name: '))
donation = float(input('Enter the amount you want to donate.: $ '))
donations.extend([name for i in range ( int(donation) // 10)])
print('You donated $ {}. Thank you {} for you donation!'.format(donation, name))
print('=-'*25)
print('[1] YES')
print('[2] NO')
answer = int(input('Would you like to make another donation? '))
if answer == 2:
makeDonation = False
shuffle(donations)
winner = choice(donations)
print('The winner was: {}' .format(winner))

How to iterate through all values in a dictionary when the key is a variable?

students = {}
grade_collect = False
id_collect = True
while id_collect == True:
ID = input(str('What is your student ID?'))
students[ID] = {}
students[ID]['Name'] = input(str('What is the student\'s name?'))
decision = input('Would you like to enter another student? (y/n)')
if decision == 'y':
continue
else:
number = input('How many assignments were given?')
id_collect = False
grade_collect = True
break
while grade_collect == True:
for x in range(int(number)):
x = input('Please enter the scores for ' + students[ID]['Name'])
print(x)
I am trying to write a program that stores Student IDs, Names, grades, and scores that are inputted by the user; and eventually printing out the average scores for each student.
Because I have the keys for the dictionary as a variable 'ID' I cannot figure out how to get the program to prompt for the grades of more than one student; it just repeats itself. In the first part of my code, I can get the dictionary to store all of the names and IDs, but when I need to go through the students by their IDs to ask the user what the grades on each assignment are, it only asks the most recent student ID in the dictionary.
I hope this is clear, thanks for any help.
Edit for clarification: By 'when the key is a variable' I meant that the variable ID is the key to each value.
ex.
{'1245': {'Name': 'Connor'}, '6789': {'Name': 'Josh'}}
The IDs aren't hard-coded, they are user input so they are a variable in the code itself. That is the part that is confusing me. Sorry for the confusion.
Since you have already created a dictionary of students ID, you technically do not need another while loop. You can simply do the following to grab each users score.
for id in students:
score = input("Please enter the scores for " + students[id]["Name"])
students[id]["Score"] = score
If there are multiple assignments, then another while-loop would be appropriate.
You can loop over all IDs using:
for id in students:
#now in each iteration, 'id' points to one of the IDs in the keys
#whatever you want to do with students[id]...
try:
for s in list(students):
students[s]
Edited to better address the question.

Python program - Help pairing elements together without using a dictionary

I"m studying for my Intro Python class and I have a proficiency exam tomorrow. In the sample problem, it asks:
"Write a program in Python to list the students who are members of the most
frequent major (assume there is only one most frequently occurring major). Your program should ask the user to input the number of students to be entered, and then ask for the name and major (you don’t know which majors will be entered ahead of time) for each of those students, on separate lines. The most frequent of the majors should be determined, and the names of the students from the most frequently occurring major should then be displayed (in any order you wish). In the following example, the user is inputting data.
How many students? 5
Enter Student Name
sue
enter major
CS
Enter Student Name
bob
enter major
PE
Enter Student Name
tom
enter major
CS
Enter Student Name
jack
enter major
CS
Enter Student Name
mary
enter major
MTH
Most Frequent Major is: CS
sue
tom
jack
So, I started to write my program, but unfortunately I'm stuck. I figured out a complicated method of gathering the majors together and finding sorting them. With that, it's easy to display the most frequent major. However, I can't seem to figure out how to assign the name values to each major. I know a dictionary cannot be used because they are immutable. Given my code, what function can I use to assign each name to a major?
num_students = int(input("enter the number of students: "))
counter = 0
major_list = []
name_list = []
while counter < num_students:
name = input("Enter Student Name: ")
name_list.append(name)
major = input("enter major: ").upper
major_list.append(major)
counter += 1
major_counter = {}
for word in major_list:
if word in major_counter:
major_counter[word] += 1
else:
major_counter[word] = 1
popular_majors = sorted(major_counter, key = major_counter.get, reverse = True)
top_major = popular_majors[0]
print("Most Frequent Mjaor is: ", top_major)
input("Press Enter to exit")
I'm really hung up on this one. Thank you so much for your help!
I your goal is to pair two elements together without dictionaries. I would:
>>> array = []
Create an array.
>>> array.append(["name","major"])
Then create a sub array with your two values
print array
[['name', 'major']]
See how there is a array within a array?
array.append(["tom","CS"])
print array
How add your stuff!
[['name', 'major'], ['tom', 'CS']]
And here is our end result!
Your task is to display a list of the students in the most frequent major. Your code does not keep track of the student names, but you need to if you are to include them in the output.
A dictionary of lists is a good way to go. As you have done, use the major as the key but, instead of counting the number of students, add each student to a list. Once you have completed collecting the user's input, you can find the most common major and print out its students. Something like this:
major_students = {}
for major, student in zip(major_list, name_list):
if major not in major_students:
major_students[major] = []
major_students[major].append(student)
In the above I have retained your method of collecting the user input into two lists which I then zipped together for processing. It's better though if you insert the user's input directly into the major_students dict as it is entered:
major_students = {}
for i in range(num_students):
name = input("Enter Student Name: ")
major = input("enter major: ").upper()
major_students[major] = major_students.get(major, []) + [name]
This results in a dictionary with the major as key and a list of students as values. Next, finding the major with the most students can be done by sorting the dictionary items using the length of the student list:
major, students = sorted(major_students.items(), key=lambda x: len(x[1]), reverse=True)[0]
print("Most Frequent Major is {} with {} students: {}".format(major, len(students), ', '.join(students)))

Categories