Java 8: praktyczny przykład - przewidywanie kolejnej daty w serii
Java 8 - praktyczny przykład
To pierwszy wpis w serii “przykłady pisane na kolanie”. Dziś będzie o wyznaczaniu kolejnej daty.
Jak powszechnie wiadomo, bardzo przydatną umiejętnością jest umiejętność przewidzenia, jaka data wypada jako kolejna po serii dat, które są od siebie mniej więcej w podobnej odległości czasowej.
Napisałam w tym celu mały programik w javie 8. Cały program znajduje się w jednym pliku. Używam wyłącznie biblioteki standardowej.
Użycie:
λ java com.kamilachyla.DateTimeSeries
2020-01-02
2020-01-04
2020-01-06
2020-01-09
2020-01-12
Average period length: 2,50
Predicted next date: 2020-01-15
λPrzewidywanie daty
Jednym z najprostszych sposobów, w jaki można to zrobić, polega na dodaniu do ostatniej daty w serii średniej odległości między wszystkimi datami. Zbudowałam sobie pomocniczą klasę RunningAverage przechowującą ostatnią widzianą datę, sumę odległości czasowych oraz ilość odległości czasowych. Na podstawie tych danych mogę użyć operacji reduce na serii dat wczytanych jako kolejne wiersze ze standardowego wejścia.
Wczytywanie danych
Zakładam, że kolejne wiersze z System.in będą zawierały daty w formacie ISO-8601, a dokładniej: spodziewam się napisów w postaci YYYY-MM-DD.
Stream<String> lines = is.lines().filter(s -> !s.isEmpty());
List<LocalDate> dates = lines
.map(toLocalDate)
.collect(Collectors.toList());Redukcja dat do RunningAverage
Kolejny krok to redukcja dat do RunningAverage:
private static RunningAverage calculateAveragePeriod(List<LocalDate> dates) {
return dates.stream().reduce(
RunningAverage.initial(),
RunningAverage::updated,
RunningAverage::plus);
}
// ... a w main():
RunningAverage average = calculateAveragePeriod(dates);Wypisanie rezultatów
Napisałam dwie funkcje implementujące Consumer<RunningAverage>, których zadaniem jest wypisanie:
- średniej odległości czasowej (
averagePeriodPrinter) oraz - przewidywanej następnej daty (
nextDatePredictor)
Użyłam ich do operowania na otrzymanym wyżej obiekcie average:
private static final Consumer<RunningAverage> averagePeriodPrinter =
(RunningAverage avg) -> System.out.println(
String.format("Average period length: %,.2f", avg.average()));
private static final Consumer<RunningAverage> nextDatePredictor =
(RunningAverage ra) -> System.out.println(
String.format("Predicted next date: %s", ra.previous.plusDays(Math.round(ra.average()))));
averagePeriodPrinter.andThen(nextDatePredictor).accept(average);Cały kod
A tu cały kod:
Źródła:
This text is part of the series java...
- 2025-21-03 - Java 24 Overview
- 2024-01-11 - Java 23 w praktyce
- 2021-27-11 - JDK 18 proposals: Java 18
- 2021-21-09 - Java 17 - RandomGenerator i spółka
- 2021-15-09 - Java 17 - co nowego?
- 2021-04-03 - Java 15 - czym są sealed classes?
- 2021-26-02 - Java 13 i 14: Bloki tekstowe i rekordy
- 2021-24-02 - Java 12 - wyrażenie switch (preview feature)
- 2021-23-02 - Java 11 - HTTP Client i uruchamianie jednoplikowych programów
- 2021-18-02 - Java 9 - co to jest JShell i dlaczego warto używać REPL-a w Javie
- 2021-12-02 - Java 10 - var, nowe metody w Optional, kolekcje "unmodifiable"
- 2021-11-02 - Java 9 - nowości w bibliotece
- 2021-10-02 - Java 9: czy mogę stworzyć z mojej aplikacji binarkę?
- 2021-10-02 - Java 9: praktyczny przykład - trzy moduły
- 2021-08-02 - Java 8: praktyczny przykład - przewidywanie kolejnej daty w serii