使用 Collection 框架计算价值的百分比

var*_*man 8 java collections spring spring-boot java-stream

我有TrainingRequest列表,其中每个元素都有 List of Feedback

@Data
class TrainingRequest{
    @Transient
    List<Feedack> feedback;
}

@Data
class Feedback{
    String Q1;
    String Q2;
}
Run Code Online (Sandbox Code Playgroud)

我需要获得 Q1、Q2 的所有给定结果并计算每个值的百分比。

List<TrainingRequest> trainingList = Optional.ofNullable(trainingRequestList).orElseGet(Collections::emptyList)
                                    .stream().map(m -> {
                                        List<Feedback> feedback = findByTrainingRequestId(m.getId());
                                        m.setFeedback(feedback);  // assigning Feedack to TrainingRequest
                                        return m;
                                    }).collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

平息所有反馈

List<Feedback> flatMap = trainingList.stream().flatMap(f -> f.getFeedback().stream()).collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

为了计算 Q1 和 Q2 的每个值,我将其分组并获取计数。我需要获得计数的每个 Q1、Q2 值的百分比。

Map<String, Map<String, Long>> map = new TreeMap<>();

map.put("Q1", flatMap.stream().collect(Collectors.groupingBy(Feedback::getQ1, Collectors.counting())));
map.put("Q2", flatMap.stream().collect(Collectors.groupingBy(Feedback::getQ2, Collectors.counting())));
Run Code Online (Sandbox Code Playgroud)

当我使用时Collectors.counting(),它给出以下输出:

{
  "Q1": {
    "unsatisfied": 2,
    "Satisfied": 1,
    "satisfied": 1
  },
  "Q2": {
    "Yes": 4
  }
}
Run Code Online (Sandbox Code Playgroud)

但我需要它按照我的预期给出百分比

{
  "Q1": {
    "unsatisfied": 50 %,
    "Satisfied": 25 %,
    "satisfied": 25 %
  },
  "Q2": {
    "Yes": 100 %
  }
}
Run Code Online (Sandbox Code Playgroud)

如何以有效的方式做到这一点?我需要优化上面的代码吗?

Cod*_*ode 2

这可能不是一个优化的答案,但您可以获得结果。创建一个地图来保存每个 Q 的总值,然后用它来计算百分比,

Map<String, Long> totalCountMap = map.entrySet().stream()
        .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().values().stream().reduce(Long::sum).orElse(0l)));

Map<String, Map<String, Long>> result = map.entrySet().stream()
        .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().entrySet().stream()
                .collect(Collectors.toMap(Map.Entry::getKey, e1 -> (e1.getValue() * 100 / totalCountMap.get(e.getKey()))))));
Run Code Online (Sandbox Code Playgroud)