簡體   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