I have a class called MonitoredData
with which describes an activity, its starting time and ending time. The attributes are activityLabel
, startTime
, endTime
. I have to group and filter these activities, using streams, the activities which have the total duration of more than 10 hours. I managed to make the sum of durations and group them according to the activity using this:
Map<String, Long> map4 = new HashMap<String, Long>();
map4 = data.stream()
.collect(
Collectors.groupingBy(
MonitoredData::getActivity,
Collectors.summingLong(MonitoredData::getDuration)
)
); //getDuration returns end Time - startTime in milliseconds
But I haven't managed to add a filter. I tried using:
.filter(Collectors.summingLong(MonitoredData::getDuration) > whatever)
but obviously it doesn't work. How can I solve this in order to make it return a Map<String, Long>
?
Using Stream.collect() The second method for calculating the sum of a list of integers is by using the collect() terminal operation: List<Integer> integers = Arrays. asList(1, 2, 3, 4, 5); Integer sum = integers. stream() .
We can use mapToInt() to convert a stream integers into a IntStream . int sum = integers. stream(). mapToInt(Integer::intValue).
A simple solution to calculate the sum of all elements in a List is to convert it into IntStream and call sum() to get the sum of elements in the stream. There are several ways to get IntStream from Stream<Integer> using mapToInt() method.
I would first do as you've already done: I'd collect the stream of MonitoredData
instances to a map, grouping by activity and summing the duration of each activity in each value:
Map<String, Long> map4 = data.stream()
.collect(Collectors.groupingBy(
MonitoredData::getActivity,
HashMap::new,
Collectors.summingLong(MonitoredData::getDuration)));
The nuance is that I'm using the overloaded version of Collectors.groupingBy
that accepts a factory for the map, because in the next step I want to remove the entries whose duration is less than 10 hours, and the spec doesn't guarantee that the map returned by the Collectors.groupingBy
methods that take either one or two arguments is mutable.
This is how I'd remove the entries that don't match:
public static final long TEN_HOURS_MS = 10 * 60 * 60 * 1000;
map4.values().removeIf(v -> v < TEN_HOURS_MS);
If you want to do everything in a single line, you might want to use Collectors.collectingAndThen
:
Map<String, Long> map4 = data.stream()
.collect(Collectors.collectingAndThen(
Collectors.groupingBy(
MonitoredData::getActivity,
HashMap::new,
Collectors.summingLong(MonitoredData::getDuration)),
m -> { m.values().removeIf(v -> v < TEN_HOURS_MS); return m; } ));
Here I've used Collectors.collectingAndThen
to modify the map returned by Collectors.groupingBy
. And, within the finisher function, I've used Collection.removeIf
, which takes a predicate and removes all the entries that match that predicate.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With