使用Java8StreamsAPI确定对象之间的关系

使用Java8StreamsAPI确定对象之间的关系,java,java-8,java-stream,reduce,Java,Java 8,Java Stream,Reduce,最近我解决了以下问题: 给出一个按时间顺序排列的LocalDateTime列表,找出邻居之间的平均持续时间 我做了以下工作: @Test public void canCalculateAverageDuration() { final LocalDateTime now = LocalDateTime.now(); final List<LocalDateTime> localDateTimes = Arrays.asList(now, now.minusHours

最近我解决了以下问题:

给出一个按时间顺序排列的LocalDateTime列表,找出邻居之间的平均持续时间

我做了以下工作:

@Test
public void canCalculateAverageDuration() {
    final LocalDateTime now = LocalDateTime.now();
    final List<LocalDateTime> localDateTimes = Arrays.asList(now, now.minusHours(5), now.plusMinutes(2));

    final List<Duration> durations = new ArrayList<>();
    localDateTimes.stream()
        .sorted()
        .reduce((first, second) -> {
            durations.add(Duration.between(first, second));
            return second;
        });

    final OptionalDouble averageNanos = durations.stream()
            .mapToDouble(Duration::toNanos)
            .average();

    final Duration average = Duration.ofNanos((long) averageNanos.orElse(0.0));
    assertThat(average).isEqualTo(Duration.parse("PT2H31M"));
}
@测试
公共无效可计算平均持续时间(){
final LocalDateTime now=LocalDateTime.now();
最终列表localDateTimes=Arrays.asList(now,now.minusHours(5),now.plusMinutes(2));
最终列表持续时间=新的ArrayList();
localDateTimes.stream()
.已排序()
.减少((第一,第二)->{
durations.add(Duration.between(first,second));
返回第二;
});
最终可选Double Averagenos=持续时间。流()
.mapToDouble(持续时间::toNanos)
.average();
最终持续时间平均值=纳米的持续时间((长)平均值-奥利斯(0.0));
assertThat(average.isEqualTo(Duration.parse(“PT2H31M”));
}

我想知道是否可以用一种更优雅的方式来解决这个问题,例如:如果可能的话,我想避免列出持续时间。您认为呢?

您可以通过迭代(即不使用流)来解决这个问题:

@测试
公共无效可计算平均持续时间(){
final LocalDateTime now=LocalDateTime.now();
最终列表localDateTimes=Arrays.asList(
现在,
现在,5小时,
现在,加号(2)
);
sort(Comparator.naturalOrder());
LocalDateTime-previous=null;
LongSummaryStatistics=新的LongSummaryStatistics();
用于(LocalDateTime日期时间:localDateTimes){
如果(上一个==null){
先前=日期时间;
}
否则{
accept(Duration.between(previous,dateTime.toNanos());
}
}
最终持续时间平均值=noos的持续时间((long)Math.ceil(stats.getAverage());
assertThat(average.isEqualTo(Duration.parse(“PT2H31M”));
}
是否更优雅取决于个人喜好,但此版本至少不使用中间系列。

我刚刚发现:

Collections.sort(localDateTimes);
final double average = IntStream.range(0, localDateTimes.size() - 1)
    .mapToLong(l ->
        Duration.between(
            localDateTimes.get(l),
            localDateTimes.get(l+1))
        .toNanos())
    .average().orElse(0.0);
assertThat(Duration.ofNanos((long) average)).isEqualTo(Duration.parse("PT2H31M"));

不,不是真的。Stream是一个管道,一次只能使用一个元素,它不能“滞后”到一侧并提供两个元素。然而,实际上,您的第一部分根本不需要流。也许如果您编写自定义收集器。但不值得complexity@user7,有一些库构建在
Stream
API之上,通过将当前元素与不久前看到的元素配对来提供窗口。但它们不是流API。收集器会做一些事情,但它会是一个收集器,所以本质上与列表相同,只是被阻塞了。Stateful
map()
也会起到作用,尽管这与流专家组对API使用的建议背道而驰。@M.Prokhorov:“您的第一部分实际上根本不需要流”是什么意思?从技术上讲,从
LongStream
开始是没有实际意义的,因为
List::size
范围是
int
。它可以是
IntStream.range
完全相同。因为我要映射到一个长值(toNanos()),所以我需要长流,因为long不能转换为int。
Collections.sort(localDateTimes);
final double average = IntStream.range(0, localDateTimes.size() - 1)
    .mapToLong(l ->
        Duration.between(
            localDateTimes.get(l),
            localDateTimes.get(l+1))
        .toNanos())
    .average().orElse(0.0);
assertThat(Duration.ofNanos((long) average)).isEqualTo(Duration.parse("PT2H31M"));