I have a list of SensorSample POJOs
public class SensorSample {
private Device.SensorType sensorType; // This is an enum
private double sample;
private long timestamp;
// Constructor
// Setters
// Getters
}
I need to group them by the timestamp
, so that all the SensorSample
s of the same day are together. Then I need to reduce them so that I have only one SensorSample
for each day and the value of its sample
is the average of the value of the sample
of all the objects for that day. Is there a way to do that with Streams?
So far I got this to group them together:
Map<Long, List<SensorSample>> yearSamples = samples.stream()
.collect(groupingBy(sample -> SECONDS_IN_A_DAY*Math.floorDiv(sample.getTimestamp(), SECONDS_IN_A_DAY)));
But I don't know how to go any further.
Something like this, I think. To find the average number of a group:
Map<Long, Double> averages = samples.stream()
.collect(groupingBy(SensorSample::getTimestamp,
averagingDouble(SensorSample::getSample)));
I didn't expand out your formula for the day, I think it's more readable if I just called getTimestamp
and leave the details out. Your code might also be more readable if you added a getDay
method to SensorSample
.
Also this would be easier to test if you provided an MCVE, as it's a little hard to test the code above with only one partial class to go on.
it seems as if you want a List<SensorSample>
as a result where each group after the groupingBy
is reduced into a single 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());
The map
logic seems a little bit large thus I'd consider refactoring it out to a method as such:
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;
}
Then the stream pipeline would become:
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());
Where Main
is the class containing the apply
method.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.