首页 > 解决方案 > 有效地计算学生列表中给定指标的统计数据

问题描述

学生.java

public class Student{
    /*
    Metrics examples (out of 100):
    mathScore:98
    scienceScore:99
    englishScore:92
    */
    private Map<String, Double> metrics = new HashMap<>();

}

统计数据

public enum Statistic {

     AVERAGE,
     MIN,
     MAX
}

结果

public class Result {
  private Statistic statistic;
  private double value;
  private String metric;
}

构建可以根据学生列表上请求的指标执行请求的静态分析的引擎的最有效方法是什么

这是一个例子:

假设我有一份学生名单。

List<Student> students = [john, json, elliot, sarah, callie, matt, leigh]; //Assume each entry is an object 

我也有我感兴趣的指标列表

List<String> metrics  =["mathScore", "scienceScore"]; //Just an example. I can add additional metrics to this list or remove them.

以及我想要执行的统计数据

List<Statistic> stats = [MIN, MAX]; //Just an example. I can request additional operations if necessary.

这是需要有效构建的方法的签名

public List<Resut> calculate( List<String> requestedMetrics, List<Statistic> requestedStatistics, List<Student> students){

}

这是我最初的想法

  1. 将 requestedMetrics 和 requestedStatistics 转换为集合以消除重复项。
  2. 遍历每个指标。对于每个指标,遍历每个统计数据并计算它。有没有更好的办法?以及如何将实现分解为更小的功能等以获得更清洁的解决方案?
  3. 创建一个缓存(地图)怎么样,这样我们就不需要一次又一次地重新处理所有内容?

这是我当前的实现

@Component
public class StatisticalAnalysis {

    @Override
    public List<Result> calculate(List<Student> students, List<String> metrics, List<Statistic> stats) {

        return analyze(new HashSet<>(students), new HashSet<>(metrics), new HashSet<>(stats));
    }

    public List<Result> analyze(HashSet<Student> students, HashSet<String> metrics, HashSet<Statistic> stats) {

        List<Result> calculate = new ArrayList<>(metrics.size());

        for (String metric : metrics) {
            for (Statistic stat : stats) {
               results.add(createResult(students, metric, stat ));
            }
        }

        return results;
    }

    private Result createResult(HashSet<Student> students, String metric, Statistic stat) {

       return new Result(metric, stat, calcStatValue(students, metric, stat));

    }

    private double calcStatValue(HashSet<Student> students, String metric, Statistic stat) {


        List<Double> values = new ArrayList<Double>(students.size());

        for(Student measurement: students){
            Double value = measurement.getMetric(metric);
            if(value!=null)
                values.add(value);
        }

        return performStatOperation(stat, values);

    }

    private double performStatOperation(Statistic stat, List<Double> values) {
        switch (stat) {
            case MIN:
                return Collections.min(values);
            case MAX:
                return Collections.max(values);
            case AVERAGE:
                return values.stream().mapToDouble(val -> val).average().orElse(0.0);
            default:
                throw new UnsupportedOperationException(String.format("Calculation of Statistic %s is currently unsupported", stat));
        }
    }


}

标签: javaalgorithmoop

解决方案


这些指标可以是一个枚举而不是一个字符串,以便它们在一个地方定义并且可以在所有代码中轻松使用。

此外,如果学生在构建后没有被修改,他们的类已经可以包含一个可以使用的列表,而不是依赖于外部方法。唯一的计算是对等级进行排序以找到最小值和最大值,考虑到指标的简短列表,这是一个微不足道的构建开销。

否则,您可以缓存学生的结果列表,并在其指标被修改时将其标记为缓存失效。


推荐阅读