You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Java Stream API如何按平均分排序?代码实现疑问及优化指导请求

Fixing the Stream Sorting Issue in Your Student Grade Program

Hey there! Let's tackle that sorting problem you're running into with your Java Stream code. I see exactly where the issue is, and we can fix it while also making your code a bit more efficient.

The Problem with Your Current Sorting Logic

Your current approach of casting the difference between two averages to int ((int) (average2 - average1)) has a critical flaw: when the difference between two averages is less than 1 (like 5.0 vs 4.9), casting to int will truncate the value to 0. This tells the comparator that the two elements are equal, so their relative order becomes unpredictable. That's not what you want for a proper descending sort by average grade.

Solution 1: Use Double.compare() for Correct Comparisons

Instead of casting the difference, use Double.compare(double d1, double d2) which is designed exactly for this scenario. It returns the correct int value (-1, 0, or 1) based on the comparison of two doubles. For descending order, you'll want to compare the second element's average to the first:

sorted((a, b) -> {
    double average1 = a.getValue().stream().mapToDouble(x -> x).average().getAsDouble();
    double average2 = b.getValue().stream().mapToDouble(x -> x).average().getAsDouble();
    return Double.compare(average2, average1);
})

Solution 2: Optimize by Calculating Averages Only Once

Even better, your current code calculates each student's average three times (once in filter, once in sorted, once in forEach) which is unnecessary overhead. Let's refactor the code to compute each average just once using map() to create a new entry with the precomputed average:

import java.util.*;
import java.util.AbstractMap.SimpleEntry;

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()
                // First, compute each student's average once and store it with their name
                .map(entry -> {
                    double average = entry.getValue().stream()
                                            .mapToDouble(Double::doubleValue)
                                            .average()
                                            .getAsDouble();
                    return new SimpleEntry<>(entry.getKey(), average);
                })
                // Filter students with average >=4.50
                .filter(entry -> entry.getValue() >= 4.50)
                // Sort descending by average using Double.compare
                .sorted((a, b) -> Double.compare(b.getValue(), a.getValue()))
                // Output the result
                .forEach(entry -> System.out.printf("%s -> %.2f%n", entry.getKey(), entry.getValue()));
    }
}

Why This Works

  • Double.compare(average2, average1) handles all double comparison cases correctly, even when the difference is a fractional number. It returns:
    • A positive integer if average2 is greater than average1
    • 0 if they are equal
    • A negative integer if average2 is less than average1
  • Precomputing the average in the map() step reduces redundant calculations, making your code faster especially when dealing with large datasets.

Testing this with your sample input will give you the correct sorted output as expected:

John -> 5.00
George -> 5.00
Alice -> 4.50

内容的提问来源于stack exchange,提问作者ccc6

火山引擎 最新活动