Сортировка и группировка объектов с несколькими полями - PullRequest
0 голосов
/ 04 сентября 2018

У меня List<MyObjects> с 4 полями:

String fieldText;
double fieldDoubleOne;
double fieldDoubleTwo;
double fieldDoubleThree;

Каков наилучший (Java-8) способ сбора и распечатки списка, отсортированного по Average (fieldDoubleOne), чтобы вывод консоли выглядел примерно так: fieldText → Среднее (fieldDoubleOne) → Среднее (fieldDoubleTwo) → Среднее (fieldDoubleThree) Предположим, публичные геттеры для всех полей. Для одного двойного поля у меня было из моего предыдущего вопроса :

Map<String, List<MyObject>> groupByFieldText = myObjectList.stream().collect(groupingBy(MyObject::getFieldText));
Map<String, Double> averageMap =   groupByFieldText.entrySet().stream()
        .map(e -> new AbstractMap.SimpleEntry<>(e.getKey(),
                e.getValue().stream()
                        .mapToDouble(d -> d.getDoubleOne()).average()
                        .orElse(0d)))
        .sorted(Comparator.comparingDouble(Map.Entry::getValue))
        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
                (v1, v2) -> v1, LinkedHashMap::new));
averageMap.entrySet().stream().sorted(Comparator.comparingDouble((Map.Entry::getValue)))
        .forEach(System.out::println);

1 Ответ

0 голосов
/ 04 сентября 2018

Вам просто нужно отсортировать записи, а не отображать их значение в double, например:

Map<String, List<MyObject>> sortedByAverageOne = groupByFieldText.entrySet().stream()
        .sorted(Comparator.comparingDouble(e -> average(e, MyObject::getDoubleOne)))
        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
                (v1, v2) -> v1, LinkedHashMap::new));

Обратите внимание, что если у вас много записей, это будет не очень эффективно, потому что оно вызывает average для каждого сравнения.

Затем, имея такую ​​отсортированную карту, вы печатаете ее следующим образом:

sortedByAverageOne.entrySet().stream()
        .map(e -> String.format(
                "%s → %f → %f → %f",
                e.getKey(),
                average(e, MyObject::getDoubleOne),
                average(e, MyObject::getDoubleTwo),
                average(e, MyObject::getDoubleThree)
        ))
        .forEach(System.out::println);

Наконец, average определяется как:

private static double average(Map.Entry<String, List<MyObject>> entry, ToDoubleFunction<MyObject> getter) {
    return average(entry.getValue(), getter);
}

private static double average(List<MyObject> list, ToDoubleFunction<MyObject> getter) {
    return list.stream().mapToDouble(getter).average().orElse(0);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...