Home > database >  Sorting two lists of objects based on common attributes
Sorting two lists of objects based on common attributes

Time:10-13

My question is similar to this one posted a few years back, but I have one additional thing that I do not understand how to do. Say I have two lists, each holding a set of objects. These objects share a common attribute:

class Student:
    def __init__(self, value) -> None:
        self.value = value
class School:
    def __init__(self, value) -> None:
        self.value = value
        self.students = []


Student_List = [Student(1), Student(1), Student(3), Student(3), Student(5)]
School_List = [School(5), School(2), School(1), School(3), School(4)]

My goal is to search for objects with matching values and then perform operations on the objects held within the lists. The current method I have is as follows:

for student in Student_List:
    for school in School_List:
         if student.value == school.value:
             school.students.append(student)
             break

This is obviously very inefficient, and finding an intersection would be much easier. However, notice how I am altering the attributes of School by appending the Student object to the School's list.

CodePudding user response:

You can create a reverse mapping that maps each school value to the corresponding school object, so that you can iterate through the list of students and efficiently obtain the matching school object with the value mapping to append the student object to:

schools = {school.value: school for school in School_List}
for student in Student_List:
    schools[student.value].students.append(student)

With this approach you can reduce the time complexity from O(n ^ 2) to O(n).

Demo: https://replit.com/@blhsing/ImpracticalSimultaneousLock

CodePudding user response:

For this specific example, I believe you could do it this way:

for school in School_List:
    school.students.extend([s for s in Student_List if s.value == school.value])

CodePudding user response:

What we need is a a quick way to look up the school, given a value. For that, I create a dictionary called school_dict:

class Student:
    def __init__(self, value) -> None:
        self.value = value
        
    def __repr__(self):
        return f"Student({self.value})"
    
class School:
    def __init__(self, value) -> None:
        self.value = value
        self.students = []
        
    def __repr__(self):
        return f"School(value={self.value}, students={self.students})"


Student_List = [Student(1), Student(1), Student(3), Student(3), Student(5)]
School_List = [School(5), School(2), School(1), School(3), School(4)]

school_dict = {s.value: s for s in School_List}

for student in Student_List:
    value = student.value
    try:
        school_dict[value].students.append(student)
    except KeyError:
        pass

School_list now is:

[
 School(value=5, students=[Student(5)]),
 School(value=2, students=[]),
 School(value=1, students=[Student(1), Student(1)]),
 School(value=3, students=[Student(3), Student(3)]),
 School(value=4, students=[])
]

Notes

  • school_dict allows quick look up to a school object, given a value
  • The try/except construct guards against those student values that do not have corresponding school.
  • Related