Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Как посчитать элементы по значениям enum

Короткий ответ

Возьмите EnumMap и увеличивайте счётчик через merge(). Ключи выводятся в порядке объявления enum:

enum Status { NEW, PAID, SHIPPED }
 
void main() {
    List<Status> orders = List.of(Status.PAID, Status.NEW, Status.PAID, Status.SHIPPED, Status.PAID);
 
    Map<Status, Integer> counts = new EnumMap<>(Status.class);
    for (Status s : orders) {
        counts.merge(s, 1, Integer::sum);
    }
    IO.println(counts);
}

Результат:

{NEW=1, PAID=3, SHIPPED=1}

Через стрим

groupingBy() с фабрикой EnumMap и counting():

enum Status { NEW, PAID, SHIPPED }
 
record Order(int id, Status status) {}
 
void main() {
    List<Order> orders = List.of(
        new Order(1, Status.PAID), new Order(2, Status.NEW), new Order(3, Status.PAID));
 
    Map<Status, Long> counts = orders.stream()
        .collect(Collectors.groupingBy(Order::status,
            () -> new EnumMap<>(Status.class), Collectors.counting()));
    IO.println(counts);
}

Результат:

{NEW=1, PAID=2}

С нулями для всех значений

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

enum Status { NEW, PAID, SHIPPED }
 
void main() {
    List<Status> orders = List.of(Status.PAID, Status.NEW, Status.PAID);
 
    Map<Status, Integer> counts = new EnumMap<>(Status.class);
    for (Status s : Status.values()) {
        counts.put(s, 0);
    }
    for (Status s : orders) {
        counts.merge(s, 1, Integer::sum);
    }
    counts.forEach((status, n) -> IO.println(status + ": " + n));
}

Результат:

NEW: 1
PAID: 2
SHIPPED: 0

Частая ошибка

Считать через HashMap: результат тот же, но порядок ключей зависит от хеш-кодов и может меняться от запуска к запуску. С EnumMap порядок всегда совпадает с порядком констант, а работает он ещё и быстрее. Второй вариант ошибки — считать по ordinal() в массиве int[]: код ломается, когда в enum добавляют новую константу в середину.

Функции из этого ответа

  • EnumMap — Словарь, ключи которого — значения одного enum. Быстрый и хранит ключи в порядке объявления.
  • Enum.values() — Методы каждого enum: values() — все константы, valueOf() — константа по имени, ordinal() и name() — номер и имя.
  • Collectors.groupingBy() — Сборщик, который раскладывает элементы по группам с общим ключом.
  • Map.merge() — Добавляет значение по ключу или объединяет его с уже существующим.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.