Java:两个或更多时间序列相加

Edd*_*Edd 5 java time-series java-stream

我有多个时间序列:

       x
|    date    | value |
| 2017-01-01 |   1   |
| 2017-01-05 |   4   |
|     ...    |  ...  |

       y
|    date    | value |
| 2017-01-03 |   3   |
| 2017-01-04 |   2   |
|     ...    |  ...  |
Run Code Online (Sandbox Code Playgroud)

令人沮丧的是,在我的数据集中,两个系列中并不总是匹配日期.对于缺少一个的情况,我想使用最后一个可用日期(如果没有,则为0).因为2017-01-03我会使用y=3x=1(从之前的日期)得到output = 3 + 1 = 4

我有以下形式的每个时间序列:

class Timeseries {
    List<Event> x = ...;
}

class Event {
    LocalDate date;
    Double value;
}
Run Code Online (Sandbox Code Playgroud)

并把它们读成了一个 List<Timeseries> allSeries

我以为我可以用流来加总它们

List<TimeSeries> allSeries = ...
Map<LocalDate, Double> byDate = allSeries.stream()
    .flatMap(s -> s.getEvents().stream())
.collect(Collectors.groupingBy(Event::getDate,Collectors.summingDouble(Event::getValue)));
Run Code Online (Sandbox Code Playgroud)

但这不会有我上面提到的缺少日期逻辑.

我怎么能做到这一点?(它不一定是溪流)

dan*_*niu 3

我想说您需要扩展 Timeseries 类以获得适当的查询功能。

class Timeseries {
    private SortedMap<LocalDate, Integer> eventValues = new TreeMap<>();
    private List<Event> eventList;

    public Timeseries(List<Event> events) {
        events.forEach(e -> eventValue.put(e.getDate(), e.getValue());
        eventList=new ArrayList(events);
    }
    public List<Event> getEvents() {
        return Collections.unmodifiableList(eventList);
    }

    public Integer getValueByDate(LocalDate date) {
        Integer value = eventValues.get(date);
        if (value == null) {
            // get values before the requested date
            SortedMap<LocalDate, Integer> head = eventValues.headMap(date);
            value = head.isEmpty()
                ? 0   // none before
                : head.get(head.lastKey());  // first before
        }
        return value;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后合并

Map<LocalDate, Integer> values = new TreeMap<>();
List<LocalDate> allDates = allSeries.stream().flatMap(s -> s.getEvents().getDate())
    .distinct().collect(toList());

for (LocalDate date : allDates) {
    for (Timeseries series : allSeries) {
        values.merge(date, series.getValueByDate(date), Integer::ad);
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:实际上,NavigableMap在这种情况下,该界面更加有用,它使得丢失数据的情况

Integer value = eventValues.get(date);
if (value == null) {
    Entry<LocalDate, Integer> ceiling = eventValues.ceilingKey(date);
    value = ceiling != null ? eventValues.get(ceiling) : 0;
}
Run Code Online (Sandbox Code Playgroud)