Java 8 считает в период скользящего окна - PullRequest
2 голосов
/ 09 марта 2019

Учитывая следующий класс и структуру данных ниже, я хочу вычислить сумму подсчета для каждого последовательного 3-часового скользящего окна, аналогичного следующим результатам:

public class Log {
    private int id;
    private LocalDateTime timestamp;
    private int count;
}
id   timestamp               count
1    2018-10-10T08:00:00     12
2    2018-10-10T08:30:00     5
3    2018-10-10T08:45:00     7
4    2018-10-10T09:10:00     9
5    2018-10-10T09:50:00     3
6    2018-10-10T10:15:00     8
7    2018-10-10T12:00:00     6
8    2018-10-10T12:30:00     1
9    2018-10-10T12:45:00     2
10   2018-10-10T17:30:00     4
11   2018-10-10T17:35:00     7

Временная метка журнала находится в порядке возрастания, и сумма итогов для каждого окна продолжительностью 3 часа (может пересекать разные дни) от первой записи. Результат будет:

2018-10-10T08:00:00 ~ 2018-10-10T10:59:00   12+5+7+9+3+8
2018-10-10T08:30:00 ~ 2018-10-10T11:29:00   5+7+9+3+8
2018-10-10T08:45:00 ~ 2018-10-10T11:44:00   7+9+3+8
2018-10-10T09:10:00 ~ 2018-10-10T12:09:00   9+3+8+6
2018-10-10T09:50:00 ~ 2018-10-10T12:09:00   3+8+6+1
2018-10-10T10:15:00 ~ 2018-10-10T13:14:00   8+6+1+2
...

У меня есть пример кода ниже, но я чувствую, что он не настолько эффективен (если существует огромное количество журналов), так как каждый раз мне приходится получать и сравнивать отфильтрованную метку времени из всех журналов. Как мне сравнить только из текущих логов до конца?

var logs = List.of();
logs.stream.map(log -> {
    var start = log.getTimeStamp();
    var end = log.getTimeStamp().plusHours(3);
    var logsWithinWindow = logs.stream().filter(l -> isWithinRange(start, end, l.getTimeStamp()));
    return logsWithinWindow.map(Log::getCount).sum();
});

1 Ответ

1 голос
/ 09 марта 2019

Если бы вы рассчитывали журналы за любую длительность, вы могли бы использовать:

int countLogsInDuration(List<Log> logs, LocalDateTime start, LocalDateTime end) {
    return logs.stream()
            .filter(log -> isWithinRange(log.getTimeStamp(), start, end))
            .mapToInt(Log::getCount)
            .sum();
}

, который опирается на

private static boolean isWithinRange(LocalDateTime logTimestamp, LocalDateTime start, LocalDateTime end) {
    // return true or false based on comparison
}

Кроме того, вычисления журналов для каждого окна продолжительностью 3 часа, по крайней мере, в вашем случае кажутся излишними, поскольку размер вашего скользящего окна составляет 30 минут. Таким образом, вы можете вычислить счетчик каждые 30 минут, например, с 8:00 до 8:30, затем с 8:30 до 9:00 и так далее. Это позволит избежать избыточно рассчитанного количества, пока ваше скользящее окно перекрывается с предыдущей продолжительностью.

...