I have a list of tuples and the tuples look like this (2, 11) which means exam 2 must be taken by student 11. The exams are numbered from 0 to however many exams there are and the same with students. I need to produce a 2D list where the first list is the exams the 0th student is taking and the second list is the exams student number 1 is taking etc. I have this code:
examsEachStudentsIsDoing = []
exams = []
number_of_students = 14
exams_to_students = [(0, 1), (0, 4), (0, 5), (0, 3), (0, 10), (0, 13), (0, 9), (0, 11), (0, 12), (0, 2), (0, 7), (0, 6), (1, 7), (2, 7), (2, 5), (2, 0), (2, 11), (2, 13), (3, 4), (4, 6), (4, 8)]
for i in range(0,number_of_students):
exams.clear()
for j in range(0,len(exams_to_students)):
if (exams_to_students[j][1]==i):
exams.append(exams_to_students[j][0])
examsEachStudentsIsDoing.append(exams)
print(examsEachStudentsIsDoing)
if i add a print line just before examsEachStudentsIsDoing.append(exams)
then i get the result:
[2]
[0]
[0]
[0]
[0, 3]
[0, 2]
[0, 4]
[0, 1, 2]
[4]
[0]
[0]
[0, 2]
[0]
[0, 2]
[[0, 2], [0, 2], [0, 2], [0, 2], [0, 2], [0, 2], [0, 2], [0, 2], [0, 2], [0, 2], [0, 2], [0, 2], [0, 2], [0, 2]]
why is it repeatedly appending on the last students exams and not each one individually
The exams
is a list. In python, lists are passed by reference, so when you are appending exams
to examsEachStudentsIsDoing
you are just appending a reference to the exams
in the examsEachStudentsIsDoing
.
At the end of the loop, for last student, the exams
is set to [0,2]
, hence for all the entries in examsEachStudentsIsDoing
, you see that value.
So instead of appending the exams
, you can append a copy of the current student's exams to the examsEachStudentsIsDoing
. To get a copy of the list you have different options - list.copy()
, copy.copy() method, or just slicing list[:]
.
Try the following code -
examsEachStudentsIsDoing = []
exams = []
number_of_students = 14
exams_to_students = [(0, 1), (0, 4), (0, 5), (0, 3), (0, 10), (0, 13), (0, 9), (0, 11), (0, 12), (0, 2), (0, 7), (0, 6), (1, 7), (2, 7), (2, 5), (2, 0), (2, 11), (2, 13), (3, 4), (4, 6), (4, 8)]
for i in range(0,number_of_students):
exams.clear()
for j in range(0,len(exams_to_students)):
if (exams_to_students[j][1]==i):
exams.append(exams_to_students[j][0])
examsEachStudentsIsDoing.append(exams.copy()) #updated
print(examsEachStudentsIsDoing)
Output:
[[2], [0], [0], [0], [0, 3], [0, 2], [0, 4], [0, 1, 2], [4], [0], [0], [0, 2], [0], [0, 2]]
To avoid such issues, you can create new exams
list for each student, so a better way to rewrite your code might be -
examsEachStudentsIsDoing = []
number_of_students = 14
exams_to_students = [(0, 1), (0, 4), (0, 5), (0, 3), (0, 10), (0, 13), (0, 9), (0, 11), (0, 12), (0, 2), (0, 7), (0, 6), (1, 7), (2, 7), (2, 5), (2, 0), (2, 11), (2, 13), (3, 4), (4, 6), (4, 8)]
for i in range(0,number_of_students):
exams = []
for j in range(0,len(exams_to_students)):
if (exams_to_students[j][1]==i):
exams.append(exams_to_students[j][0])
examsEachStudentsIsDoing.append(exams)
print(examsEachStudentsIsDoing)