Given 2 dictionaries of:
- the students' id and how many points they've got on each problem:
user_probstat_dict = {'106095014': [3, 1, 1], '106095029': [3, 1, 0], '106095033': [3, 1, 0]}
- the students' id and the number of problem that they've been cheated:
user_cheatprob_dict = {'106095029': [1, 3], '106095033': [3]}
My aim is to change the score into 0 for those problems that have been cheated, like for the id '106095029', this student's original score:
'106095029': [3, 1, 0]
should be changed into:
'106095029': [0, 1, 0]
Since maybe not all of the students have cheated, the user_cheatprob_dict
won't always include all of the student ids.
Here's my code:
for u, c in user_cheatprob_dict.items():
for ci in c:
prob_ind = ci - 1
user_probstat_dict.update({u:???})
My thought is to first loop over the user_cheatprob_dict
, if there's a student that has problems cheated, then take the key (student id = u
) and use the update function to replace the value into 0.
The ???
in my code is the part where I don't know how to refer to only the specific value(by the index prob_ind
)in the list.
I only knew that if I want to change the whole value, I just need to place 0 at the ???
part.
Thanks!
CodePudding user response:
You can use dictionary traversal as follows:
user_probstat_dict = {'106095014': [3, 1, 1], '106095029': [3, 1, 0], '106095033': [3, 1, 0]}
user_cheatprob_dict = {'106095029': [1, 3], '106095033': [3]}
for i in list(user_cheatprob_dict.keys()):
for j in user_cheatprob_dict[i]:
user_probstat_dict[i][j-1] = 0
print(user_probstat_dict)
Output: Note that the index of user_cheatprob_dict is offset by -1 to get the correct problem index
{'106095014': [3, 1, 1], '106095029': [0, 1, 0], '106095033': [3, 1, 0]}
CodePudding user response:
I have 2 solutions, depending on your needs. Also, those solutions are safe: it won't raise if a student's id is missing in one or another dict, or if a cheated problem's number doesn't correspond to any problem.
1. Recompute your solution
This is the more compact one, but it consumes more memory since it recreates a new dictionary. Use it only on small enough samples. The advantage is that you let your input unchanged.
def recompute(points_dict, cheat_dict):
"""create a new points dict, but doesn't modify the input"""
return {
idd: [p * ((i 1) not in cheat_dict.get(idd, [])) for i, p in enumerate(points)]
for idd, points in points_dict.items()
}
When multiplied with a number, a boolean corresponds to the value 1 or 0 (respectively for True or False).
2. Replace directly in the input
Less compact, but also less memory consumption. And your input is changed!
def replace(points_dict, cheat_dict):
"""replace the points in the input: input modified"""
for idd, numbers in cheat_dict.items():
if idd in points_dict:
for num in numbers:
if num <= len(points_dict[idd]):
points_dict[idd][num - 1] = 0