Calculate the sum of values in Map via the Stream Api
There is a collection ArrayList
that stores objects of the Student(<HashMap<Subject, Integer> rating, String name>)
class.
You need to calculate the average score for a specific 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
- the total score for a particular subject (subject) of all students. -
countMarkInGroup
- the number of such estimates. -
studentsInGroup
- collection with all Student objects. -
getRating()
- returnsHashMap<Subject, Integer>
with a list of subjects and grades for to him. -
subject
- the subject in which I want to learn the average score.
Student student1 = new Student(new HashMap<>() {{
put(BIOLOGY, 8);
put(MATH, 4);
put(ENGLISH, 10);
put(PHYSIC, 6);
}}, "Ivanov Ivan Ivanovich");
Student student2 = new Student(new HashMap<>() {{
put(MATH, 5);
put(ASTRONOMY, 6);
put(CHEMISTRY, 2);
}}, "Petrov Petr Petrovovich");
Student student3 = new Student(new HashMap<>() {{
put(ASTRONOMY, 7);
put(PHYSIC, 4);
put(HISTORY, 5);
}}, "Vasiliev Vasiliy Vasilievich");
Student student4 = new Student(new HashMap<>() {{
put(ASTRONOMY, 4);
put(MATH, 10);
}}, "Sergeev Sergei Sergeevich");
Group group1 = new Group("TEEO", new ArrayList<>() {{
add(student1);
add(student2);
}});
Group group2 = new Group("THEORETICAL PHYSICS", new ArrayList<>() {{
add(student3);
add(student4);
}});
Faculty faculty1 = new Faculty("PHYSICS FACULTY", new ArrayList<>() {{
add(group1);
add(group2);
}});
faculty1.averageMarkOnSubjectOnFaculty(MATH);
public void averageMarkOnSubjectOnFaculty(Subject subject) {
averageMarkOnSomeSubjectOnFaculty = facultyList.stream()
.map(e -> e.getStudentsInGroup())
.map(e -> e.iterator().next())
.filter(e -> e.getRating().containsKey(subject))
.mapToInt(e -> e.getRating().get(subject))
.average()
.orElse(0.0);
if (averageMarkOnSomeSubjectOnFaculty == 0)
System.out.println("There are no students on the faculty " + getNameFaculty() +
" which learning " + subject + ".");
else System.out.println("On the faculty " + getNameFaculty() + " in the subject " + subject +
" average mark " + averageMarkOnSomeSubjectOnFaculty);
}
1
Author: robert0801, 2020-08-28
2 answers
Let's say you have a student like this:
class Student{
Map<String, Integer> rating;
String name;
public Student(String name){
rating = new HashMap<>();
this.name = name;
}
public Student rate(String subject, Integer rate){
rating.put(subject, rate);
return this;
}
}
Then the counting method can be as follows:
private static Double avgRate(String subject, List<Student> students){
return students
.stream()
.mapToInt(student -> student.rating.get(subject))
.average()
.orElse(0);
}
UPD: If we use faculty and groups, we can do this:
private static Double avgRate(String subject, Faculty faculty){
return faculty
.getGroups()
.stream()
.flatMap(group -> group.getStudents().stream())
.mapToInt(student -> student.rating.get(subject))
.average()
.orElse(0);
}
Where we extract a list of groups from the faculty, then use flatmap
to open a stream with students from each group. And then as in the first example.
2
Author: Alexey R., 2020-08-28 21:55:59
When using the e.getRating().entrySet().iterator().next()
construct, you will actually get a random item, which will lead to incorrect data.
package com.somepackage;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;
public class Main {
@Getter
@Builder
@ToString
@EqualsAndHashCode
static class Subject {
private String name;
}
@Getter
@Builder
@ToString
@EqualsAndHashCode
static class Student {
private Map<Subject, Integer> rating;
private String name;
}
private static List<Subject> prepareSubjects(String...names) {
return Arrays.stream(names)
.map(n -> Subject.builder()
.name(n)
.build())
.collect(Collectors.toList());
}
private static List<Student> prepareStudents(List<Subject> subjects, String...names) {
return Arrays.stream(names)
.map(n -> Student.builder()
.name(n)
.rating(subjects.stream()
.collect(
Collectors.toMap(
s -> s,
s -> ThreadLocalRandom.current().nextInt(1, 6))))
.build())
.collect(Collectors.toList());
}
private static <T> T randomValue(
final List<T> values) {
return values.get(
ThreadLocalRandom.current().nextInt(
values.size()));
}
public static void main(String[] args) {
List<Subject> subjects =
prepareSubjects(
"Java", "C#", "Kotlin", "Scala");
List<Student> students =
prepareStudents(
subjects,
"Ivanova", "Petrov", "Sidorov", "Fedorova");
Map<Subject, Double> ratings =
students.stream()
.flatMap(s -> s.getRating().entrySet().stream())
.collect(Collectors.groupingBy(
e -> e.getKey(),
HashMap::new,
Collectors.averagingDouble(e -> e.getValue())));
Subject randomSubject =
randomValue(subjects);
double randomSubjectRating1 =
students.stream()
.mapToInt(s -> s.getRating().get(randomSubject))
.average()
.orElse(0.0);
double randomSubjectRating2 =
students.stream()
.flatMap(s -> s.getRating().entrySet().stream())
.filter(e -> randomSubject.equals(e.getKey()))
.collect(Collectors.averagingDouble(e -> e.getValue()));
System.out.println("Students: " + students);
System.out.println("Ratings: " + ratings);
System.out.println("Rating by random subject #1: " + randomSubjectRating1);
System.out.println("Rating by random subject #2: " + randomSubjectRating2);
}
}
1
Author: Alexandr, 2020-08-28 19:42:16