Java 使用流式api搜索列表中的值并保持搜索位置(标准化测量数据)

Java 使用流式api搜索列表中的值并保持搜索位置(标准化测量数据),java,lambda,java-8,java-stream,Java,Lambda,Java 8,Java Stream,我得到了测量数据的列表。此列表中的条目包含timstamp和数据本身。每15分钟一个条目会有或多或少的变化,但也可能会丢失数据点或出现较大的抖动。 我需要的是建立一个标准化的数据列表,在这里我每15分钟就有一个条目。作为数据,我可以只做前面的测量 输入: A B C D E F |----|---------|-----|--|-----------------------|--> t 输出: |----|---

我得到了测量数据的列表。此列表中的条目包含timstamp和数据本身。每15分钟一个条目会有或多或少的变化,但也可能会丢失数据点或出现较大的抖动。 我需要的是建立一个标准化的数据列表,在这里我每15分钟就有一个条目。作为数据,我可以只做前面的测量

输入:

A    B         C     D  E                       F
|----|---------|-----|--|-----------------------|--> t
输出:

|----|----|----|----|----|----|----|----|----|----|--> t
A    B    B    C    C    E    E    E    E    E    F
如何使用Java8中的流以优雅而高效的方式实现这一点? 它不能是
data.stream().filter([…]).findFirst()
,因为可能有很多数据点-总是从一开始就搜索太昂贵。 我做了同样的测试,输入数据已经对齐15分钟,这样我就可以做了

public NormalizedData normalizeData(List<MeasurementData> data, Instant t) {
    return data.stream()
        .filter(d -> Objects.equals(d.getTimestamp().getEpochSecond(), t.getEpochSecond()))
        .map(d -> new NormalizedData(t, d))
        .findFirst()
        .orElse(...);
}
公共规范化数据规范化数据(列表数据,即时t){
返回data.stream()
.filter(d->Objects.equals(d.getTimestamp().getEpochSecond(),t.getEpochSecond())
.map(d->新规范化数据(t,d))
.findFirst()
.orElse(…);
}
对于所有的
瞬间t
,它太慢了

有什么想法吗?我们应该能够以某种方式将搜索位置存储在流中,并在下一轮中继续。或者一个完全不同的方法。
如果有一个与标准流兼容的第三方流库解决方案(如
StreamEx
),这也是一个选项。

下面是一些示例代码,说明如何填充缺失的数据点

下面的许多代码都不是必需的,因为它只是设置数据以显示代码实际如何工作

代码所做的是使用流API收集功能,将上次收集的
数据点
与当前的
数据点
进行比较,如果时间戳之间的差异大于15分钟,则插入一个新条目

从测试数据中可以看出,C和D以及E和F之间存在30分钟的差异。这意味着C和E的数据将被复制

代码

如果我正确理解OP,下面是forked的试用:

// assume the data is sorted by time
final List<Pair<Integer, String>> data = N.asList(Pair.of(1, "A"), Pair.of(16, "B"), Pair.of(46, "C"),
    Pair.of(60, "D"), Pair.of(76, "E"), Pair.of(151, "F"));
final int startTime = data.get(0).left();
final int interval = 15;

final Map<Integer, Pair<Integer, String>> map = StreamEx.of(data).filter(p -> (p.left() - startTime) % interval == 0).toMap(p -> p.left());

IntStreamEx.rangeClosed(startTime, data.get(data.size() - 1).left(), interval) 
      .forEach(t -> map.computeIfAbsent(t, k -> Pair.of(t, map.get(t - interval).right())));

final List<Pair<Integer, String>> result = StreamEx.of(map).sortedBy(e -> e.getKey()).map(e -> e.getValue()).toList();

System.out.println(result.stream().map(p -> p.right).collect(Collectors.joining("--")));
//假设数据按时间排序
最终列表数据=N.asList(第(1,“A”)对、第(16,“B”)对、第(46,“C”)对,
一对(60,“D”)、一对(76,“E”)、一对(151,“F”);
final int startTime=data.get(0.left();
最终整数间隔=15;
最终映射=streamx.of(data).filter(p->(p.left()-startTime)%interval==0.toMap(p->p.left());
IntStreamEx.rangeClosed(startTime,data.get(data.size()-1.left(),interval)
.forEach(t->map.computeIfAbsent(t,k->Pair.of(t,map.get(t-interval.right()));
最终列表结果=streamx.of(map).sortedBy(e->e.getKey()).map(e->e.getValue()).toList();
System.out.println(result.stream().map(p->p.right).collect(collector.joining(“--”);

您是否尝试过在
.paralell()
中运行它?这可能会提高速度,但不会提高效率。当您的数据按时间戳排序时,可以使用二进制搜索。您可以通过将
list.get(list.size()-1)
移动到
addPointIfRequired
方法中来简化此过程,因为它将始终使用目标列表的最后一个元素。
A 2018-07-11T01:22:45.628Z
B 2018-07-11T01:37:45.628Z
C 2018-07-11T01:52:45.628Z
C 2018-07-11T02:07:45.628Z
D 2018-07-11T02:22:45.628Z
E 2018-07-11T02:37:45.628Z
E 2018-07-11T02:52:45.628Z
F 2018-07-11T03:07:45.628Z
// assume the data is sorted by time
final List<Pair<Integer, String>> data = N.asList(Pair.of(1, "A"), Pair.of(16, "B"), Pair.of(46, "C"),
    Pair.of(60, "D"), Pair.of(76, "E"), Pair.of(151, "F"));
final int startTime = data.get(0).left();
final int interval = 15;

final Map<Integer, Pair<Integer, String>> map = StreamEx.of(data).filter(p -> (p.left() - startTime) % interval == 0).toMap(p -> p.left());

IntStreamEx.rangeClosed(startTime, data.get(data.size() - 1).left(), interval) 
      .forEach(t -> map.computeIfAbsent(t, k -> Pair.of(t, map.get(t - interval).right())));

final List<Pair<Integer, String>> result = StreamEx.of(map).sortedBy(e -> e.getKey()).map(e -> e.getValue()).toList();

System.out.println(result.stream().map(p -> p.right).collect(Collectors.joining("--")));