Как использовать MergeSort для сортировки объектов маринования на основе атрибута? - PullRequest
0 голосов
/ 04 июня 2018

Я создаю программу базы данных и пытаюсь включить систему сортировки.У меня есть несколько объектов, которые все Students.У этих студентов есть три атрибута: name, grade и average.

Я пытаюсь заставить программу сортировать средние значения учащихся, а затем отображать учащихся в порядке наивысшего значения досамый низкий средний.Мне удалось открыть внешний файл, в котором хранятся объекты, а затем сохранить средние значения каждого учащегося в списке.Когда у меня есть список, я могу использовать MergeSort для сортировки списка.Однако я не могу понять, как использовать отсортированный список для сортировки и отображения каждого объекта.Я пытался использовать поиск, чтобы найти, где находится среднее значение в списке объектов, поэтому я могу отобразить этот объект, но не могу заставить его работать правильно.

Моя программа выглядит следующим образом:

import pickle

class Student():
    def __init__(self,nam,grd,avg):
        self.name = nam
        self.grade = grd
        self.average = avg

    def get_details(self):
        print(self.name, self.grade, self.average)

    def create_item():
        new_student = Student(input("Enter name: "),input("Enter grade: "), input("Enter average: "))
        save_object(new_student, 'student_data.pkl')

def clear_database():
    file = open('student_data.pkl', 'w')
    file.close()

def save_object(obj, filename):
    with open(filename, 'ab') as output:
        pickle.dump(obj, output, pickle.HIGHEST_PROTOCOL)

def unpickle_database(filename):
    with open(filename, 'rb') as f:
        while True:
            try:
                yield pickle.load(f)
            except EOFError:
                break

def display_database():
    print("\nName:               Grade:              Average:            ")
    for student in unpickle_database('student_data.pkl'):
        property_list = [student.name, student.grade, student.average]
        print(''.join([v.ljust(20,' ') for v in property_list]))

def delete_student(student_to_delete, filename):
    students = list(unpickle_database(filename))
    del students[student_to_delete-1]
    clear_database()
    for student in students:
        save_object(student, filename)

def store_grades_in_list():
    students = list(unpickle_database('student_data.pkl'))
    students_grade = []
    for student in students:
        students_grade.append(int(student.grade))
    return students_grade

def store_averages_in_list():
    students = list(unpickle_database('student_data.pkl'))
    students_average = []
    for student in students:
        students_average.append(int(student.average))
    return students_average

def merge(st1, st2, st3):
    i1 = i2 = i3 = 0
    n1, n2 = len(st1), len(st2)

    while i1 < n1 and i2 < n2:
        if st1[i1] < st2[i2]:
            st3[i3] = st1[i1]
            i1 = i1 + 1
        else:
            st3[i3] = st2[i2]
            i2 = i2 + 1
        i3 = i3 + 1

    while i1 < len(st1):
        st3[i3] = st1[i1]
        i1 = i1 + 1
        i3 = i3 + 1

    while i2 < len(st2):
        st3[i3] = st2[i2]
        i2 = i2 + 1
        i3 = i3 + 1

def mergeSort(st):
    n = len(st)
    if n > 1:
        m = n//2
        st1, st2 = st[:m], st[m:]
        mergeSort(st1)
        mergeSort(st2)
        merge(st1, st2, st)
    return st

def bin_search(x):
    my_list = store_averages_in_list()
    bottom = 0
    top = len(my_list)-1
    found = False
    location = -1
    while (bottom <= top) and not(found):
        middle = int((bottom + top)/2)

        if (my_list[middle] == x):
            location = middle
            found = True
        elif (my_list[middle] < x):
            bottom = middle + 1
        else:
            top = middle -1
    return location

while True:
    user_input = input("\nType \"Clear\" to clear the database. Type \"Add\" to add a student. Type \"Display\" to display the database contents. Type \"Quit\" to quit the program. Type \"Remove\" to remove a student. Type \"Search\" to serach for an average. Type \"Sort av\" to display sorted list of averages.\n")
    if user_input == "Quit":
        break
    elif user_input == "Clear":
        clear_database()
        print("\nThe database has been cleared.")
    elif user_input == "Add":
        Student.create_item()
        print("\nThe student has been added. The updated database is: ")
        display_database()
    elif user_input == "Display":
        display_database()
    elif user_input == "Remove":
        student_to_delete = int(input("Type the student number that you would like to delete: "))
        delete_student(student_to_delete,'student_data.pkl')
        print("\nThe student has been deleted. The updated database is: ")
        display_database()
    elif user_input == "Display Characteristics":
        store_chars_in_list()
    elif user_input == "Sort av":
        print(mergeSort(store_averages_in_list()))
    elif user_input == "Sort gr":
        print(mergeSort(store_grades_in_list()))
    elif user_input == "Search":
        print(bin_search(int(input("Enter average to search for: "))))

1 Ответ

0 голосов
/ 04 июня 2018

Таким образом, есть две вещи, которые вам нужно сделать, чтобы выполнить это.

  1. Вместо того, чтобы передавать список студентов средние в функцию (и) слияния, вам нужнопередать список Student самих объектов.
  2. Функция mergesort не изменится, но функция merge изменится.Поскольку элементы в списке больше не числа, а объекты Student, вместо сравнения st1[i1] < st2[i2] или аналогичных, вам нужно сравнить что-то вроде st1[i1].average < st2[i2].average или тому подобное.Таким образом, вы сортируете не список средних , а список Student с.Затем, когда у вас есть отсортированный список учащихся, вы можете отобразить его так, как вам нравится.

В этом ответе намеренно содержится как можно меньше явного кода, потому что кажется, что этот вопрос назначен в качестве школьного задания.и вам следует взять предоставленную мною информацию и поиграть с ней:)

Примечание: если вы просто хотите отсортировать список Student s и вам не нужны илиЕсли вы хотите написать mergesort самостоятельно, будет работать следующий код:

students = ... # list of Student
sorted_students = list(sorted(students, key=attrgetter('average'))

с использованием функции attrgetter из библиотеки operator.

...