Question:
Create a program that keeps information about some students and their grades.
You will receive an integer number - n.
Then, you will receive 2 \* n rows of input.
First, you will receive the student's name. Аfter that, you will receive their grade.
If the student does not exist, add them.
Keep track of all of the grades of each student.
When you finish reading the data, keep only the students which have an average grade higher or equal to 4.50.
Order the filtered students by their average grade in descending order.
Print the students and their average grade in the following format:
"{name} -\> {averageGrade}"
Format the average grade to the second decimal place.
Test input:
5
John
5.5
John
4.5
Alice
6
Alice
3
George
5
Test output:
John -> 5.00
George -> 5.00
Alice -> 4.50
My answer:
import java.util.*;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = Integer.parseInt(scanner.nextLine());
Map<String, List<Double>> records = new HashMap<>();
while(n > 0){
String name = scanner.nextLine();
double grade = Double.parseDouble(scanner.nextLine());
records.putIfAbsent(name, new ArrayList<>());
records.get(name).add(grade);
n--;
}
records.entrySet().stream().filter(item -> {
double average = item.getValue().stream().mapToDouble(x -> x).average().getAsDouble();
return average >= 4.50;
}).sorted((a, b) -> {
double average1 = a.getValue().stream().mapToDouble(x -> x).average().getAsDouble();
double average2 = b.getValue().stream().mapToDouble(x -> x).average().getAsDouble();
return (int) (average2 - average1);
}).forEach(pair -> {
double average = pair.getValue().stream().mapToDouble(x -> x).average().getAsDouble();
System.out.printf("%s -> %.2f%n", pair.getKey(), average);
});
}
}
I'm pretty sure I'm not doing the sorting by average part correctly but I can't seem to find another way to go about it as the sorting requires an int and the average will always be a double?
Any pointers/explanation will be greatly appreciated!
CodePudding user response:
After taking input you can follow below code snippet
We can make a new map with name as key and average as value instead of calculating average multiple times
Map<String, Double> recordsWithAverage = records.entrySet()
.stream()
.collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().stream().mapToDouble(x -> x).average().getAsDouble()));
recordsWithAverage.entrySet()
.stream()
.filter(e -> e.getValue() >= 4.50)
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
.forEach(pair -> {
System.out.printf("%s -> %.2f%n", pair.getKey(), pair.getValue());
});
CodePudding user response:
Try this.
public static void main(String[] args) throws IOException {
String input = "5\r\n"
"John\r\n"
"5.5\r\n"
"John\r\n"
"4.5\r\n"
"Alice\r\n"
"6\r\n"
"Alice\r\n"
"3\r\n"
"George\r\n"
"5\r\n";
Scanner in = new Scanner(input);
int size = in.nextInt();
Map<String, List<Double>> map = new HashMap<>();
for (int i = 0; i < size; i)
map.computeIfAbsent(in.next(), k -> new ArrayList<>()).add(in.nextDouble());
map.entrySet().stream()
.map(e -> Map.entry(e.getKey(),
e.getValue().stream().mapToDouble(v -> v).average().getAsDouble()))
.filter(e -> e.getValue() >= 4.50)
.sorted(Collections.reverseOrder(Comparator.comparing(Entry::getValue)))
.forEach(e -> System.out.printf("%s -> %.2f%n", e.getKey(), e.getValue()));
}
output:
George -> 5.00
John -> 5.00
Alice -> 4.50