in use-cases/vaccination-scheduling/src/main/java/org/acme/vaccinationscheduler/domain/solver/VaccinationSolution.java [94:164]
public VaccinationSolution(VaccinationSchedule schedule, DistanceCalculator distanceCalculator) {
this.vaccineTypeList = schedule.getVaccineTypeList();
this.vaccinationCenterList = schedule.getVaccinationCenterList();
this.appointmentList = schedule.getAppointmentList();
Function<Appointment, Triple<VaccinationCenter, LocalDateTime, VaccineType>> tripleFunction
= (appointment) -> Triple.of(
appointment.getVaccinationCenter(),
appointment.getDateTime().truncatedTo(ChronoUnit.HOURS),
appointment.getVaccineType());
Set<Appointment> scheduledAppointmentSet = schedule.getPersonList().stream()
.map(Person::getAppointment)
.filter(Objects::nonNull)
.collect(Collectors.toSet());
Map<Triple<VaccinationCenter, LocalDateTime, VaccineType>, List<Appointment>> appointmentListMap
= schedule.getAppointmentList().stream()
.collect(groupingBy(tripleFunction, LinkedHashMap::new, Collectors.collectingAndThen(
Collectors.toList(), subAppointmentList -> subAppointmentList.stream().sorted(
Comparator.comparing(Appointment::getDateTime).thenComparing(Appointment::getBoothId))
.collect(Collectors.toList()))));
vaccinationSlotList = new ArrayList<>(appointmentListMap.size());
Map<Triple<VaccinationCenter, LocalDateTime, VaccineType>, VaccinationSlot> vaccinationSlotMap = new HashMap<>(appointmentListMap.size());
long nextVaccinationSlotId = 0;
for (Map.Entry<Triple<VaccinationCenter, LocalDateTime, VaccineType>, List<Appointment>> entry : appointmentListMap.entrySet()) {
Triple<VaccinationCenter, LocalDateTime, VaccineType> triple = entry.getKey();
List<Appointment> appointmentList = entry.getValue();
VaccinationCenter vaccinationCenter = triple.getLeft();
LocalDateTime startDateTime = triple.getMiddle();
VaccineType vaccineType = triple.getRight();
List<Appointment> unscheduledAppointmentList = appointmentList.stream()
.filter(appointment -> !scheduledAppointmentSet.contains(appointment))
.collect(Collectors.toList());
int capacity = appointmentList.size();
VaccinationSlot vaccinationSlot = new VaccinationSlot(nextVaccinationSlotId++, vaccinationCenter,
startDateTime, vaccineType, unscheduledAppointmentList, capacity);
vaccinationSlotList.add(vaccinationSlot);
vaccinationSlotMap.put(triple, vaccinationSlot);
}
List<Person> personList = schedule.getPersonList();
personAssignmentList = new ArrayList<>(personList.size());
Location[] fromLocations = personList.stream().map(Person::getHomeLocation).toArray(Location[]::new);
Location[] toLocations = vaccinationCenterList.stream().map(VaccinationCenter::getLocation).toArray(Location[]::new);
// One single call to enable bulk mapping optimizations
long[][] distanceMatrix = distanceCalculator.calculateBulkDistance(fromLocations, toLocations);
for (int personIndex = 0; personIndex < personList.size(); personIndex++) {
Person person = personList.get(personIndex);
Map<VaccinationCenter, Long> distanceMap = new HashMap<>(vaccinationCenterList.size());
for (int vaccinationCenterIndex = 0; vaccinationCenterIndex < vaccinationCenterList.size(); vaccinationCenterIndex++) {
VaccinationCenter vaccinationCenter = vaccinationCenterList.get(vaccinationCenterIndex);
long distance = distanceMatrix[personIndex][vaccinationCenterIndex];
distanceMap.put(vaccinationCenter, distance);
}
PersonAssignment personAssignment = new PersonAssignment(person, distanceMap);
Appointment appointment = person.getAppointment();
// Person.appointment is non-null with pinned persons but maybe also with non-pinned persons from draft runs
if (appointment != null) {
VaccinationSlot vaccinationSlot = vaccinationSlotMap.get(tripleFunction.apply(appointment));
if (vaccinationSlot == null) {
throw new IllegalStateException("The person (" + person
+ ") has a pre-set appointment (" + appointment
+ ") that is not part of the schedule's appointmentList with size ("
+ schedule.getAppointmentList().size() + ")");
}
personAssignment.setVaccinationSlot(vaccinationSlot);
}
personAssignmentList.add(personAssignment);
}
this.score = schedule.getScore();
}