Printing a square matrix using conditions and operators in python

I am writing a function to match elements of a tuple (G) using if, elif conditions. The tuple G is a 10 by 3 tuple. G[0] is information of student ‘S1’ with supervisor ‘SP1’ and panel ‘P1’ which consists of three members.

The data structure is as follows:

[('S1', 'A8', ('A1', 'A2', 'A3')), ('S2', 'A5', ('A1', 'A2', 'A3')), ('S3', 'A6', ('A3', 'A4', 'A5')), ('S4', 'A1', ('A6', 'A7', 'A8')), ('S5', 'A4', ('A6', 'A7', 'A8')), ('S6', 'A2', ('A9', 'A10', 'A11')), ('S7', 'A3', ('A8', 'A9', 'A10')), ('S8', 'A4', ('A12', 'A13', 'A10')), ('S9', 'A10', ('A12', 'A13', 'A14')), ('S10', 'A11', ('A12', 'A13', 'A7'))]

The definition of the match matrix is:

  • “0” means there is no conflict between the student panels. This means students can be allocated into the same timeslot on the same day but must be in different rooms. So, for example, S1, S8, S9 and S1 have no conflict with each other.
  • “1” indicates there is a conflict between the student panels. This is because they have at least one common panel member. So these students can not be allocated into the same timeslot on the same day. For example, S1, S2 and S3 have common panel members, so they conflict with each other.
  • “ 1* ” indicates the students’ conflict with each other in terms of both panels and supervisors. So these students can not be allocated into the same timeslot on the same day. For example, the S2 supervisor is a panel member of S3.
  • “*” indicates students’ conflict with each other in term supervisor only. In this case, these students can be allocated into the same timeslot on the same day in different rooms, but plenty will be added to the timetable quality.
  • The total of conflicts column shows the number of conflicts in each row. For example, S1 has 2 conflicts, S2 has 2 conflicts, S3 has 2 conflicts, and so on.

I am having trouble finding a way to match the elements based on the given definitions and print a matrix:

Tried code:

def matrix_generator(D1,D2,Match1):
    for i in range(len(D1)):
        for j in range(len(D2)):
            
            if D1[2][i] !=  D2[2][j] and (D1[1] == D2[2][j]) or (D2[1] == D1[2][j]):
                 Match1[i][j] = "*" 
            if D1[2][i] ==  D2[2][j]:
                Match1[i][j] = "1"
            elif (D1[1] == D2[2][j]) or (D2[1] == D1[2][j]) and (D1[2][i] !=  D2[2][j]):
                    Match1[i][j] = "*1" 
    return Match1
           
Match1 = [[0 for i in range(10)] for j in range(10)]

for i in range(0,9):
    for j in range(0,9):
        aa= matrix_generator(G[i],G[j], Match1)
print(aa)

I am getting output:

[['1', '*1', '*1', 0, 0, 0, 0, 0, 0, 0], ['1', '1', '*1', 0, 0, 0, 0, 0, 0, 0], ['*1', '*1', '1', 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

The desired output is

Can someone please explain how it can be done?

I’m sorry, I having trouble understanding your data structure. You say

that you have a “10 by 3 tuple” G, but then you give a list. Is that

list supposed to be G? It is not clear if the list is G or if G is some

other tuple that you haven’t shown.

You then say that G[0] is information of student ‘S1’ with supervisor

‘SP1’ and panel ‘P1’ which consists of three members, but the list shown

doesn’t include either the string ‘SP1’ or ‘P1’. So that’s confusing. It

isn’t clear which parts are meant to be variable names and which parts

are meant to be literal strings.

I’m going to guess what your requirements are. Here is an example for

a single student:

# Student panel

P1 = ('Teacher A', 'Teacher B', 'Teacher C')



# Student record:

S1 = ('Student A', 'Supervisor A', P1)

Then you have a list of such student records:

G = [S1, S2, S3, S4, ...]

where S2, S3 etc are also student records defined similarly to S1.

My guess is that each student is unique, so there are no student

records with the same student, but the supervisors and teachers are not.

Is my understanding close to what you have?

Have you considered using an object-oriented design? That may be a

little bit easier to understand, using named attributes instead of

numbered items.

class StudentRecord:

    def __init__(self, name, supervisor, *panel):

        if len(panel) != 3:

            raise ValueError('panel must have three members')

        self.name = name

        self.supervisor = supervisor

        self.panel = set(panel)

    def conflict(self, other):

        if not isinstance(other, StudentRecord):

            raise TypeError('must compare only with another student')

        if self is other:

            # Comparing a student with themselves.

            return '-'

        assert self.name != other.name

        # Check for conflict with panels or supervisors.

        panel_confilct = self.panel & other.panel

        supervisor_conflict = (self.supervisor == other.supervisor

                               or self.supervisor in other.panel

                               or other.supervisor in self.panel)

        if panel_conflict and supervisor_conflict:

            return '1*'

        elif panel_conflict:

            return '1'

        elif supervisor_conflict:

            return '*'

        else:

            # No conflict.

            return '0'

You can give the class a __str__ method if you want it to print

nicely, and methods to compare them.

Then you can create your list of students like this:

G = [StudentRecord('Student A', 'Supervisor A', 'Teacher A', 'Teacher B', 'Teacher C'),

     StudentRecord('Student B', 'Supervisor A', 'Teacher D', 'Teacher C', 'Teacher E'),

     StudentRecord('Student C', 'Supervisor C', 'Teacher F', 'Teacher H', 'Teacher Z'),

     ...,

     ]

Verify that the student names are unique:

assert len(set(student.name for student in G)) == len(G)

That checks that if you extract all the student’s names, and put them in

a set, the length of the set equals the number of students. That works

because sets cannot contain duplicates.

Now you want to produce a match array by comparing each student with

every other student.

M = []

for student in G:

    row = []

    for other in G:

        row.append(student.conflict(other))

    M.append(row)

Does this help?

Note: I have not tested any of my code above. It may contain bugs or

typos.