如何使用 MergeSort 根据属性对 pickle 对象进行排序?
How to use MergeSort to sort pickle objects based on an attribute?
我正在创建一个数据库程序,我正在尝试合并一个排序系统。我有多个对象,都是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: "))))
所以你需要做两件事来完成这个。
- 不是将学生平均值的列表传递给合并排序函数,而是需要传递
Student
对象本身的列表。
mergesort
函数不会改变,但 merge
函数会。由于列表中的元素不再是数字,而是 Student
对象,因此您需要比较 st1[i1].average < st2[i2].average
之类的东西,而不是比较 st1[i1] < st2[i2]
或类似的东西。这样,您排序的不是 平均值 的列表,而是 Student
的列表。然后,一旦你有了一个排序的学生列表,你就可以随心所欲地显示它。
这个答案有意尽可能少地包含明确的代码,因为这个问题感觉就像是学校布置的作业,你应该接受我提供的信息并尝试一下:)
旁注:如果您只是想对 Student
的列表进行排序并且不需要或不想自己编写合并排序,则以下代码将起作用:
students = ... # list of Student
sorted_students = list(sorted(students, key=attrgetter('average'))
使用 operator
库中的 attrgetter
函数。
我正在创建一个数据库程序,我正在尝试合并一个排序系统。我有多个对象,都是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: "))))
所以你需要做两件事来完成这个。
- 不是将学生平均值的列表传递给合并排序函数,而是需要传递
Student
对象本身的列表。 mergesort
函数不会改变,但merge
函数会。由于列表中的元素不再是数字,而是Student
对象,因此您需要比较st1[i1].average < st2[i2].average
之类的东西,而不是比较st1[i1] < st2[i2]
或类似的东西。这样,您排序的不是 平均值 的列表,而是Student
的列表。然后,一旦你有了一个排序的学生列表,你就可以随心所欲地显示它。
这个答案有意尽可能少地包含明确的代码,因为这个问题感觉就像是学校布置的作业,你应该接受我提供的信息并尝试一下:)
旁注:如果您只是想对 Student
的列表进行排序并且不需要或不想自己编写合并排序,则以下代码将起作用:
students = ... # list of Student
sorted_students = list(sorted(students, key=attrgetter('average'))
使用 operator
库中的 attrgetter
函数。