How to compute an average value for group using stream. Below code which I would like to transform to stream solution.
public static void main(String[] args) {
List<Item> items = Arrays.asList(
new Item("A", 1.0),
new Item("A", 1.0),
new Item("B", 1.0)
);
System.out.println(averageForGroup(items));
}
public static double averageForGroup(List<Item> items) {
Set<String> uniqueGroups = new HashSet<>();
double sum = 0;
for (Item i : items) {
String groupName = i.getGroupName();
if (!uniqueGroups.contains(groupName)) {
uniqueGroups.add(groupName);
}
sum += i.getValue();
}
return sum / uniqueGroups.size();
}
Item class:
public class Item {
private String groupName;
private Double value;
// Full-args constructor
// Getters and setters
}
I tried something like this:
public static double averageForGroup2(List<Item> items) {
return items.stream()
.collect(Collectors.groupingBy(
Item::getGroupName,
Collectors.averagingDouble(Item::getValue)) )
.entrySet().stream()
.mapToDouble(entry -> entry.getValue())
.sum();
}
But method sums up averages, so not what I expect. If it was possible to revert summing with grouping it may return excepted result.
double result = items.stream()
.collect(
Collectors.collectingAndThen(
Collectors.groupingBy(
Item::getGroupName,
Collectors.summingDouble(Item::getValue)),
map -> map.values().stream().mapToDouble(Double::doubleValue).sum() / map.size()));
To make it more readable, you can do it in two operations:
long distinct = items.stream().map(Item::getGroupName).distinct().count();
double sums = items.stream().mapToDouble(Item::getValue).sum();
System.out.println(sums / distinct);
You can do it in a single pass, but requires a custom collector...
You want something like:
Map<String, Double> map = items.stream() // Stream
.collect(Collectors.groupingBy( // Group to map
Item::getGroupName, // Key is the groupName
Collectors.averagingDouble(Item::getValue))); // Value is the average of values
To get result average of a particular group, get the value from the Map
:
double averageForA = map.get("A");
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