I have a class Film with the following fields
String name;
double duration;
Collection<String> categories;
My task is to return a Map<String, Double>
that represents the average duration by category.
I have to use Stream API of Java.
My idea is to form entries of String
for the category and List<Double>
where the elements are the different durations, and then to use stream api method map and map it to map of string and average. But I am not sure how to do it. Can someone help me how to do it?
You can use the three-argument form of Collectors.groupingBy()
with a downstream Collectors.averagingDouble()
collector to do it in a single pass. Java 17 example (Including using Map.Entry
to emulate a 2-element tuple or pair class):
import java.util.*;
import java.util.stream.*;
public class Demo {
private record Film(String name, double duration,
Collection<String> categories) {}
public static void main(String[] args) {
var films = List.of(new Film("The Terminator", 1.783,
List.of("Sci-Fi", "Action")),
new Film("Alien", 1.95,
List.of("Sci-Fi", "Horror")));
Map<String,Double> avgDurations = films.stream()
// Get a stream of (Category, Duration) pairs
.flatMap(film ->
film.categories().stream()
.map(cat -> Map.entry(cat, film.duration())))
// Group by Category and calculate the average of each
// group's Durations in a TreeMap
.collect(Collectors.groupingBy(Map.Entry::getKey,
TreeMap::new,
Collectors.averagingDouble(Map.Entry::getValue)));
System.out.println(avgDurations);
}
}
When compiled and run, prints out
{Action=1.783, Horror=1.95, Sci-Fi=1.8664999999999998}