我想强制同一系列学生的学生组处于同一课程类型的同一时间段和同一房间。
这是我的尝试:
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() 方法以仅考虑连续的课程 ID,但收到以下警告:未检查 varargs 参数的泛型数组创建。
我怎样才能更好地写出这种约束呢?
我能想到的最简单的就是这样的:
要理解的关键部分是
groupBy
- 你的studentGroup
和subject
一起形成一个组密钥。具有相同键的所有课程都属于同一组。在该组中,countDistinct
收集器将计算有多少个不同的实例对timeslot
和room
。(注意:你必须Pair
自己实现。它可以像一行 Java 一样简单record
。)您可能会想要替换
countDistinct
为toList
,以便您可以访问实际的对。我不会。集合不是增量的,增量是求解器性能的关键。