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



我有一份SensorSample POJOs 的列表

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方法的类。

最新更新