Как принудительно сгруппировать уроки для одной и той же серии учеников в одном временном интервале и в одном и том же таймфолде/оптапланнере комнаты?

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

Это моя попытка:

Constraint seminarsGroupedInTheSameTimeslot(ConstraintFactory constraintFactory){
        return constraintFactory
                //select each 2 pair of different lessons
                .forEachUniquePair(Lesson.class,
                        //with the same group
                        Joiners.equal((lesson) -> lesson.getStudentGroup().getGroup()),
                        //with the same series
                        Joiners.equal((lesson) -> lesson.getStudentGroup().getName()),
                        //with the same subject
                        Joiners.equal(Lesson::getSubject),
                        //with the same Seminar type
                        Joiners.equal((lesson) -> lesson.getType().equals(LessonType.SEMINAR))
                )
                //check if the lessons have different timeslots and rooms
                .filter(((lesson, lesson2) -> {
                    return !(lesson.getTimeslot().equals(lesson2.getTimeslot()) &&
                            lesson.getRoom().equals(lesson2.getRoom()));
                }))
                .penalize(HardSoftScore.ONE_HARD)                
                .asConstraint("Seminars should be grouped in the same timeslot and room");
    }

Я знаю, что это не лучшее решение, поскольку оно не масштабируемо и дает штраф за каждую пару уроков, нарушающих ограничение (т. е. в случае, если анализируются 10 уроков и только один экземпляр уроков нарушает ограничение, оценка будет быть -9 вместо -1).

Я попытался добавить метод ifNotExists(), чтобы учитывать только идентификатор последовательных уроков, но получил следующее предупреждение: Непроверенное создание массива дженериков для параметра varargs.

Как мне лучше написать такое ограничение?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
0
60
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Самое простое, что я мог придумать, было бы примерно так:

forEach(Lesson.class)
.filter(lesson -> lesson.getType() == SEMINAR)
.groupBy(
    Lesson::getStudentGroup, 
    Lesson::getSubject, 
    countDistinct(lesson -> Pair.of(lesson.getTimeslot(), lesson.getRoom())))
.filter((group, subject, timeslotAndRoomCount) -> timeslotAndRoomCount > 1)
.penalize(ONE_HARD, 
     (group, subject, timeslotAndRoomCount) -> timeslotAndRoomCount - 1)
...

Ключевая часть, которую нужно понять, это groupBy — ваши studentGroup и subject вместе образуют групповой ключ. Все уроки с одинаковым ключом попадают в одну группу. Внутри этой группы сборщик countDistinct вычислит, сколько существует различных экземпляров пар timeslot и room. (Примечание: вам придется реализовать Pair самостоятельно. Это может быть просто однострочный Java record.)

У вас может возникнуть соблазн заменить countDistinct на toList, что даст вам доступ к реальным парам. Я бы не стал. Коллекции не являются инкрементными, а инкрементальность является ключом к производительности решателя.

Я добавил реализованную пару (простую запись) в ограничение, протестировал ограничение и заметил значительное улучшение решения Solver. Большое спасибо!

Diallo Francis Patrick 11.04.2024 16:56

Другие вопросы по теме