Как отсортировать List объектов с двумя полями

Имеется List<Consumer> myList, в котором объект представлен полем consumer и полем termClarification.
Поля заказчиков повторяются, поля уточнений сроков имеют два типа: "есть", "нет".
Необходимо вывести заказчиков и процент соотношения уточнений сроков.

Я использовал код, который группирует уникальных заказчиков и количество уточнений:

Map<Consumer, Integer> consumerMap = new HashMap<>();
for (Consumer object : consumerList) {
    if (consumerMap.containsKey(object)) {
        consumerMap.put(object, consumerMap.get(object) + 1);
    } else {
        consumerMap.put(object, 1);
    }
}

Как отсортировать значения в процентном соотношении?


Ответы (1 шт):

Автор решения: Alex Rudenko

Во-первых, начиная с Java 8 Consumer -- это функциональный интерфейс с методом void accept(T t). Во избежание недоразумений стоит использовать другое название класса, например, MyConsumer или Customer.

Имеется List myList, в котором объект представлен полем consumer и полем termClarification.

То есть, предположим, что класс Consumer можно представить так:

@Data // lombok-аннотация для генерации геттеров/сеттеров/equals/hashCode/toString
class MyConsumer {
    private String consumer;
    private boolean termClarification;
}

Для расчёта процента соотношений уточнений нужно вычислить количество объектов, где termsClarification == true и поделить на общее количество объектов. Для накопления статистики можно использовать массив int[].

Для расчёта можно применить Stream API и коллектор toMap с функцией слияния.

List<MyCustomer> customers; // ...
Map<String, int[]> stats = customers.stream()
    .collect(Collectors.toMap(
        MyCustomer::getConsumer, // ключ - поле consumer
        customer -> new int[]{1, customer.isTermClarification() ? 1 : 0},
        (arr1, arr2) -> new int[]{arr1[0] + arr2[0], arr1[1] + arr2[1]}
    ));

Статистика stats - хэш-мапа, которая не поддерживает порядок сортировки.
Для сортировки по значениям нужно применить компаратор по значению частоты:

stats.entrySet()
     .stream() // Stream<Map.Entry<String, int[]>>
     .sorted(Map.Entry.comparingByValue(
         Comparator.comparingDouble((int[] arr) -> (double) arr[1] / arr[0]).reversed()
         ).thenComparing(Map.Entry.comparingByKey())
     )
     .forEach(e -> System.out.println(e.getKey() + ": " + (double) e.getValue()[1] / e.getValue()[0]));

Примечание: код не тестирован

→ Ссылка