Ваш вопрос был немного неясен, поэтому я попытался немного упростить логику c для себя. Я придумал фрагмент кода, чтобы вычислить процент четных / нечетных целых чисел в IntStream
(что не так сильно отличается от того, что вы пытаетесь сделать).
IntStream.range(0, 101).boxed()
.collect(Collectors.groupingBy(integer -> (integer % 2) == 0 ? "even" : "odd",
Collectors.collectingAndThen(Collectors.counting(), aLong -> aLong + " %")));
Обратите внимание на использование collectingAndThen()
это давайте нам сначала collect
значения, затем отобразим результат в другое значение, используя mapper/finisher
.
В вашем случае это будет преобразовано во что-то подобное
map.put("Q1", flatMap.stream().collect(Collectors.groupingBy(Feedback::getQ1,
Collectors.collectingAndThen(Collectors.counting(), count -> (count / flatMap.size()) * 100.00 + " %")));
map.put("Q2", flatMap.stream().collect(Collectors.groupingBy(Feedback::getQ2,
Collectors.collectingAndThen(Collectors.counting(), count -> (count / flatMap.size()) * 100.00 + " %")));
ОБНОВЛЕНИЕ
Поскольку вы специально спрашивали об оптимизации, вот пара моментов, на которые
1. Не создавайте новую коллекцию, если вы можете повторно использовать существующую
// this code is unnecessarily creating a new collection
List<TrainingRequest> trainingList = Optional.of(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());
, ее можно упростить до этой
// to avoid NullPointerExceptions
trainingRequestList = trainingRequestList == null ? Collections.emptyList() : trainingRequestList;
// because java is pass by reference we are able to do this
trainingRequestList.forEach(m -> m.setFeedback(findByTrainingRequestId(m.getId())));
2. Не собирайте, если вы собираетесь снова собрать поток
// to hold the count of Q1 an Q2
final Map<String, Integer> count = new HashMap<>();
// Order(n), n = trainingRequests count
trainingRequestList.forEach(trainingRequest -> {
List<Feedback> feedbacks = findByTrainingRequestId(trainingRequest.getId());
// Order(m), m = feedbacks count
feedbacks.forEach(f -> {
count.merge("Q1", f.getQ1(), Integer::sum);
count.merge("Q2", f.getQ2(), Integer::sum);
});
trainingRequest.setFeedback(feedbacks);
}
// finally we can collect the percentage
// Order(1)
int totalCountOfFeedbacks = count.values().stream().mapToInt(Integer::intValue).sum();
Map<String, String> result = count.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, entry -> 100.00 * (entry.getValue() / totalCountOfFeedbacks ) + " %"));
Обратите внимание, что эти оптимизации не повлияют на тот факт, что ваш логин c в настоящее время Order(n * m)
, вам будет трудно предоставить дальнейшие подсказки, фактически не смотря на код.