繁体   English   中英

使用Java Streams按属性将对象列表组合在一起,并将它们减少为具有另一个属性平均值的新对象列表

[英]Using Java Streams to group together a List of objects by an attribute and reduce them to a new list of object with the average of another attribute

我有一个SensorSample POJO列表

public class SensorSample {

    private Device.SensorType sensorType; // This is an enum
    private double sample;
    private long timestamp;

    // Constructor

    // Setters

    // Getters

}

我需要按timestamp对它们进行分组,以便同一天的所有SensorSample都在一起。 然后我需要减少它们,这样我每天只有一个SensorSample ,其sample的值是当天所有对象的sample值的平均值。 有没有办法用Streams做到这一点?

到目前为止,我将它们组合在一起:

Map<Long, List<SensorSample>> yearSamples = samples.stream()
                .collect(groupingBy(sample -> SECONDS_IN_A_DAY*Math.floorDiv(sample.getTimestamp(), SECONDS_IN_A_DAY)));

但我不知道如何进一步。

我认为,这样的事情。 要查找组的平均数:

Map<Long, Double> averages = samples.stream()
  .collect(groupingBy(SensorSample::getTimestamp,
   averagingDouble(SensorSample::getSample)));

我没有扩展你当天的公式,我认为如果我只是调用getTimestamp并保留详细信息,它更具可读性。 如果向SensorSample添加了getDay方法,那么您的代码可能更具可读性。

如果你提供了一个MCVE,这也会更容易测试,因为测试上面的代码只需要一个部分类就可以了。

看起来好像你想要一个List<SensorSample> ,其中groupingBy之后的每个组被简化为一个SensorSample

List<SensorSample> result = samples.stream()
                .collect(groupingBy(sample -> SECONDS_IN_A_DAY*Math.floorDiv(sample.getTimestamp(), SECONDS_IN_A_DAY))
                .entrySet()
                .stream()
                .map(e -> {
                    SensorSample sensorSample = new SensorSample();
                    sensorSample.setTimestamp(e.getKey());
                    double average = e.getValue().stream()
                            .mapToDouble(SensorSample::getSample)
                            .average().orElse(0);
                    sensorSample.setSample(average);
                    sensorSample.setSensorType(e.getValue().get(0).getSensorType());
                    return sensorSample;
                }).collect(Collectors.toList());

map逻辑似乎有点大,因此我会考虑将其重构为一个方法:

private static SensorSample apply(Map.Entry<Long, List<SensorSample>> e) {
        SensorSample sensorSample = new SensorSample();
        sensorSample.setTimestamp(e.getKey());
        double average = e.getValue().stream()
                .mapToDouble(SensorSample::getSample)
                .average().orElse(0);
        sensorSample.setSample(average);
        sensorSample.setSensorType(e.getValue().get(0).getSensorType());
        return sensorSample;
}

然后流管道将变为:

List<SensorSample> result = samples.stream()
                .collect(groupingBy(sample -> SECONDS_IN_A_DAY*Math.floorDiv(sample.getTimestamp(), SECONDS_IN_A_DAY))
                .entrySet()
                .stream()
                .map(Main::apply)
                .collect(Collectors.toList());

Main是包含apply方法的类。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM