Reputation: 150
I'm a completely newbie, so I ask you not to swear too much)
There is a collection (ArrayList) that keeps objects of the class Student (<HashMap <Subject, Integer> rating, String name>). I must calculate the average score for a particular subject using the Stream API. I Tried to do it like this:
sumOnSubjectInGroup = studentsInGroup.stream()
.filter(e -> e.getRating().entrySet().iterator().next().getKey().equals(subject))
.mapToInt(e -> e.getRating().entrySet().iterator().next().getValue())
.reduce(0, (x, y) -> x + y);
countMarkInGroup = (int) studentsInGroup.stream()
.filter(e -> e.getRating().entrySet().iterator().next().getKey().equals(subject))
.count();
return (double) sumOnSubjectInGroup / countMarkInGroup;
where sumOnSubjectInGroup is the sum of all students' subject scores. countMarkInGroup - the number of such marks. studentsInGroup is a collection with all Student objects. getRating () - returns a HashMap <Subject, Integer> with a list of items and ratings for it. But obviously I got the wrong result
Upvotes: 0
Views: 816
Reputation: 19545
You may use Collectors.averagingInt
to calculate the average value without separate calculation of sum and count by subject.
import java.util.*;
import java.util.stream.*;
class Student {
String name;
Map<String, Integer> rating;
public Student(String name, Map<String, Integer> grades) {
this.name = name;
this.rating = grades;
}
public String getName() { return name; }
public Map<String, Integer> getRating() { return rating; }
}
public class Main {
public static void main(String args[]) {
List<Student> students = Arrays.asList(
new Student("John", Map.of("Math", 90, "Physics", 94, "Chemistry", 93, "English", 92)),
new Student("Jack", Map.of("Math", 73, "Physics", 76, "English", 89)),
new Student("Jane", Map.of("Math", 87, "Chemistry", 91, "French", 94)),
new Student("Joel", Map.of("Math", 81, "Physics", 79, "French", 88))
);
students
.stream()
.flatMap(s -> s.getRating().entrySet().stream())
.collect(Collectors.groupingBy(
Map.Entry::getKey, Collectors.averagingInt(Map.Entry::getValue)))
.entrySet()
.forEach(System.out::println);
}
}
Output:
English=90.5
Chemistry=92.0
French=91.0
Math=82.75
Physics=83.0
Upvotes: 2
Reputation: 18430
You can use .average()
to calculate average and use containsKey
to check existence in the map to filter and get the score.
Double average = studentsInGroup.stream()
.filter(e -> e.getRating().containsKey(subject))
.mapToInt(e -> e.getRating().get(subject))
.average()
.orElse(0.0);
Upvotes: 5