Search code examples
pythonlistlist-comprehension

Sorting students and what exams they are doing


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


Solution

  • 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)