I am currently working on some Java code that has a goal:
- Receive list of
Collection<ForecastPerDate>(see below); - Find items that have
date >= today; - Get the
valueof the item with date closest to today (minimumdiff); - Floor it and round it;
- If no data has been found, it should fallback to
0with a log message.
public record ForecastPerDate(String date, Double value) {}
My implementation so far seems pretty efficient and sane to me, but I don't like mutating variables or state (I am becoming more of a Haskell dev lately haha) and always quite liked using the Streams API of Java.
Just FYI the project uses Java 17 so that helps. I assume this probably can be solved with a reduce() function and some accumulator but I am unclear on how to, at least without causing more than one iteration.
Here is the code:
@Override
public Long getAvailabilityFromForecastData(final String fuCode,
final String articleCode,
final Collection<ForecastPerDate> forecasts) {
if (forecasts == null || forecasts.isEmpty()) {
log.info(
"No forecasts received for FU {} articleCode {}, assuming 0!",
fuCode,
articleCode
);
return 0L;
}
final long todayEpochDay = LocalDate.now().toEpochDay();
final Map<String, Double> forecastMap = new HashMap<>();
long smallestDiff = Integer.MAX_VALUE;
String smallestDiffDate = null;
for (final ForecastPerDate forecast : forecasts) {
final long forecastEpochDay = LocalDate.parse(forecast.date()).toEpochDay();
final long diff = forecastEpochDay - todayEpochDay;
if (diff >= 0 && diff < smallestDiff) {
// we look for values in present or future (>=0)
smallestDiff = diff;
smallestDiffDate = forecast.date();
forecastMap.put(forecast.date(), forecast.value());
}
}
if (smallestDiffDate != null) {
final Double wantedForecastValue = forecastMap.get(smallestDiffDate);
if (wantedForecastValue != null) {
return availabilityAmountFormatter(wantedForecastValue);
}
}
log.info(
"Resorting to fallback for FU {} articleCode {}, 0 availability for article! Forecasts: {}",
fuCode,
articleCode,
forecasts
);
return 0L;
}
private Long availabilityAmountFormatter(final Double raw) {
return Math.round(Math.floor(raw));
}
EDIT: In the end after all suggestions here, a nice little algorithm came out:
private static Long toEpochDay(final String date) {
return LocalDate.parse(date).toEpochDay();
}
@Override
public Long getAvailabilityFromForecastData(final String fuCode,
final String articleCode,
final Collection<ForecastPerDate> forecasts) {
final long today = LocalDate.now().toEpochDay();
final String fallbackMessage = "Resorting to fallback for FU {} articleCode {},"
+ " 0 availability for article! Forecasts: {}";
if (forecasts == null) {
log.info(fallbackMessage, fuCode, articleCode, null);
return 0L;
}
final Optional<ForecastPerDate> result = forecasts.stream()
.filter(fpd -> toEpochDay(fpd.date()) > today)
.min(Comparator.comparing(fpd -> toEpochDay(fpd.date()) - today));
if (result.isPresent()) {
return availabilityAmountFormatter(result.get().value());
} else {
log.info(fallbackMessage, fuCode, articleCode, forecasts);
return 0L;
}
}
private Long availabilityAmountFormatter(final Double raw) {
return Math.round(Math.floor(raw));
}