Если в постановке проблемы - PullRequest
2 голосов
/ 12 апреля 2020

Я пытаюсь составить план, который представляет собой список классов, которые могут быть добавлены только после того, как требуемые классы были завершены или сопутствующие классы принимаются в том же семестре.

Ниже у меня есть код, который почти работает, но он всегда повторно использует классы, даже если они уже были завершены / использованы. Я пытался предотвратить это с помощью and (class_list[i][0] not in classes_done), я надеялся, что он не будет go в операторе if, но кажется, что его игнорируют.

Остальная часть этого оператора if работает нормально. (class_list[i][3] == '' or class_list[i][3] in classes_done) имеет ли этот класс обязательный завершенный класс, если да, был ли он завершен? (class_list[i][2] in classes_for_semester or class_list[i][2] == '') имеет ли этот класс сопутствующий класс, если да, находится ли он в class_for_semester или уже завершен?

Переменная class_list организована следующим образом ['name', 'credit', 'co-requisite', 'required completed classes', 'empty']. Я добавил другие переменные в качестве комментариев, чтобы показать, как они выглядят.

class PlanGenerator:
def generator(max_credit_allowed, min_credit_allowed, classes_done, class_list):
    classes_for_semester = []
    credits_for_semester = 0
    semester = 0
    full_plan = []
    # class_list = [['MA 241 ', '4', '', '', ''], ['PS 150 ', '3', 'MA 241 ', '', ''], ['UNIV 101', '1', '', '', ''], ['COM 122', '3', '', '', ''], ...]
    # max_credit_allowed = 16
    # min_credit_allowed = 12
    # classes_done=['UNIV 101']
    while len(classes_done) != len(class_list): # keep going until all classes are used
        while int(min_credit_allowed) > credits_for_semester: # keep going until at least the minimum credits are in the semester
            semester += 1
            for i in range(len(class_list)): # looping over the class list
                if int(class_list[i][1]) + credits_for_semester < max_credit_allowed: #if this class was to be added would it go over the max credit for semester if yes go to next class
                    if (class_list[i][3] == '' or class_list[i][3] in classes_done) and (class_list[i][2] in classes_for_semester or class_list[i][2] in classes_done or class_list[i][2] == '') and (class_list[i][0] not in classes_done):
                        classes_for_semester.append(class_list[i][0])
                        credits_for_semester += int(class_list[i][1])
                        print('classes for semester', classes_for_semester)
                        print('semester credits', credits_for_semester)
            classes_done.append(classes_for_semester)
            full_plan.append(semester)
            full_plan.append(classes_for_semester)
            print('full plan', full_plan)
            classes_for_semester = []
            credits_for_semester = 0
    print('done')
    print(full_plan)

Надеюсь, мое объяснение имеет смысл. Может быть, кто-то может понять мою ошибку и помочь мне найти хорошее решение. Также, если у вас есть что-нибудь, что могло бы сделать этот код более простым, пожалуйста, дайте мне знать.

Очень признателен

1 Ответ

1 голос
/ 12 апреля 2020

Во-первых, ваша while int(min_credit_allowed) > credits_for_semester строка ведет к бесконечному l oop. Его нужно изменить на

while len(classes_done) != len(class_list) and int(min_credit_allowed) > credits_for_semester: # Remove the second while loop

Во-вторых, вы добавляете список в список, поэтому вы получаете двумерный список для classes_done с classes_done.append(classes_for_semester)

This должно быть

classes_done += classes_for_semester

, чтобы вы добавляли элементы из classes_for_semester в classes_done вместо добавления списка.

Ваш новый код должен выглядеть следующим образом:

def generator(max_credit_allowed, min_credit_allowed, classes_done, class_list):
    classes_for_semester = []
    credits_for_semester = 0
    semester = 0
    full_plan = []
    # class_list = [['MA 241 ', '4', '', '', ''], ['PS 150 ', '3', 'MA 241 ', '', ''], ['UNIV 101', '1', '', '', ''], ['COM 122', '3', '', '', ''], ...]
    # max_credit_allowed = 16
    # min_credit_allowed = 12
    # classes_done=['UNIV 101']
    while len(classes_done) != len(class_list) and int(min_credit_allowed) > credits_for_semester: # keep going until at least the minimum credits are in the semester
        semester += 1
        for i in range(len(class_list)): # looping over the class list
            if int(class_list[i][1]) + credits_for_semester < max_credit_allowed: #if this class was to be added would it go over the max credit for semester if yes go to next class
                if (class_list[i][3] == '' or class_list[i][3] in classes_done) and (class_list[i][2] in classes_for_semester or class_list[i][2] in classes_done or class_list[i][2] == '') and (class_list[i][0] not in classes_done):
                    classes_for_semester.append(class_list[i][0])
                    credits_for_semester += int(class_list[i][1])
                    print('classes for semester', classes_for_semester)
                    print('semester credits', credits_for_semester)
        classes_done += classes_for_semester
        full_plan.append(semester)
        full_plan.append(classes_for_semester)
        print('full plan', full_plan)
        classes_for_semester = []
        credits_for_semester = 0
    print('done')
    print(full_plan)

Я бы настоятельно рекомендовал использовать None вместо '' для несуществующих значений, чтобы вы могли выполнить простую проверку value is None вместо проверки на равенство для пустой строки.

Для списков передаваемой информации о классах я бы изменил их на классы, словари или именованные кортежи (узнайте больше о них здесь ), чтобы вы могли легко ссылаться на значения по имени а не цифры. class_list[i].class_name или class_list[i]['class_name'] намного легче отлаживать в будущем, чем индексы magi c. Вы даже можете изменить for l oop, чтобы использовать фактические данные класса в качестве переменной вместо i in range(len(class_list)), например, так:

for c in class_list:
   if int(c.credits) .... # Using a class or namedtuple approach as suggested above

И еще одна незначительная вещь, которая, вероятно, не является большой проблемой но может стать проблемой, если эти списки будут расти долго: рассмотрите возможность использования sets вместо lists для хранения таких вещей, как classes_done и classes_for_semester. Он также предотвращает сохранение дубликатов (при условии, что вы не хотите хранить один и тот же класс более одного раза).


Чтобы привести конкретный пример предложения namedtuple, вы можете сделать следующее :

from collections import namedtuple
ClassList = namedtuple('ClassList', ['class_name', 'credits', 'coreq', 'prereq'])

class_list = [
    ClassList(class_name='MA 241', credits=4, coreq=None, prereq=None),
    ClassList(class_name='PS 150', credits=3, coreq='MA 241', prereq=None),
    # ...
]

Так что твой для л oop становится

for c in class_list:
    if c.credits + credits_for_semester < max_credits_allowed:
        if (c.prereq is None or c.prereq in classes_done) and \
           (c.coreq in classes_for_semester or c.coreq in classes_done or c.coreq is None) and \
           (c.class_name not in classes_done):
            classes_for_semester.append(c.class_name)
            credits_for_semester += c.credits
classes_done += classes_for_semester
full_plan.append(semester)
full_plan.append(classes_for_semester)
classes_for_semester = []
credits_for_semester = 0
...