Java: подсчет вхождений элементов списка с groupBy

Пройдите тест, узнайте какой профессии подходите

Я предпочитаю
0%
Работать самостоятельно и не зависеть от других
Работать в команде и рассчитывать на помощь коллег
Организовывать и контролировать процесс работы

Быстрый ответ

Для подсчёта количества элементов в списке с использованием Java Streams и метода groupBy используйте следующий код:

Java
Скопировать код
Map<Key, Long> frequencyMap = items.stream()
    .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

В этом сегменте Key – это тип данных элементов вашего списка, а items – это ваш список или коллекция. Function.identity() здесь выступает образом формирования групп, то есть в качестве ключа используется значение элемента.

Кинга Идем в IT: пошаговый план для смены профессии

Подробное рассмотрение GroupBy

Разберём, как функционирует Collectors.groupingBy. Этот метод осуществляет операции, аналогичные SQL-запросам, но вместо баз данных он работает с коллекциями в Java. Он принимает два аргумента:

  • Функцию классификации, определяющую группу для каждого элемента.
  • Коллектор, реализующий сокращение количества элементов. Например, с помощью Collectors.counting(), можно подсчитать элементы в группе.

Подсчёт пользовательских объектов

Если требуется подсчитать элементы, основываясь на определённых свойствах объектов, используйте структуру вида:

Java
Скопировать код
Map<CustomType, Long> counts = customList.stream()
    .collect(Collectors.groupingBy(CustomType::getAttribute, Collectors.counting()));

Одновременный подсчёт

Для максимально эффективной работы в многопоточной среде стоит использовать groupingByConcurrent, обеспечивающий потокобезопасность:

Java
Скопировать код
ConcurrentMap<Key, Long> concurrentFrequencyMap = items.parallelStream()
    .collect(Collectors.groupingByConcurrent(Function.identity(), Collectors.counting()));

Это гарантирует надёжность и безошибочность обработки данных в многопоточных условиях.

Производительность и альтернативы

Несмотря на удобство использования, Collectors.groupingBy не всегда является самым быстрым способом обработки данных.

Вариант с использованием ToMap

Для увеличения производительности можно задействовать Collectors.toMap с функцией объединения Map::merge:

Java
Скопировать код
Map<Key, Long> frequencyMapAlternative = items.stream()
    .collect(Collectors.toMap(key -> key, val -> 1L, Math::addExact));

StreamEx для работы с примитивными типами

При работе с примитивными типами для оптимизации производительности можно применить библиотеку StreamEx:

Java
Скопировать код
Map<Key, Integer> frequencyMapStreamEx = StreamEx.of(items)
    .groupingBy(Function.identity(), MoreCollectors.countingInt());

Для работы с StreamEx необходимо добавить соответствующую библиотеку в ваш проект.

Визуализация

Метод groupBy поможет вам сортировать данные. В качестве примера рассмотрим сгруппированные по эрам коллекционные монеты:

Java
Скопировать код
Map<Era, Long> coinCountByEra = coins.stream().collect(
    Collectors.groupingBy(Coin::getEra, Collectors.counting())
);
ЭраКоличество монет
Бронзовая2
Серебряная4
Золотая1

Проверенный метод вывода на печать

Для вывода результатов на экран используйте entrySet:

Java
Скопировать код
frequencyMap.entrySet().forEach(entry -> 
    System.out.println(entry.getKey() + ": " + entry.getValue()));

Сложные случаи

Обработка нулевых значений

Чтобы исключить null-элементы из подсчёта, предварительно воспользуйтесь фильтром:

Java
Скопировать код
Map<Object, Long> frequencyMapWithNulls = items.stream()
    .filter(Objects::nonNull)
    .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

Сложные типы

Сложные типы возможно сгруппировать, создав составной ключ или Pair:

Java
Скопировать код
Map<Pair<AttributeType1, AttributeType2>, Long> complexMap = complexList.stream()
    .collect(Collectors.groupingBy(
        item -> new AbstractMap.SimpleEntry<>(item.getAttribute1(), item.getAttribute2()),
        Collectors.counting()
    ));

Углубленная обработка

Вы также можете выполнять дополнительную обработку полученных данных: сортировать, фильтровать или преобразовывать их для последующего анализа.

Полезные материалы

  1. Collectors (Java Platform SE 8 ) — Официальная документация метода Collectors.groupingBy.
  2. Java Stream collect() Method Examples | DigitalOcean — Статья о методе collect() в контексте groupingBy.
  3. DZone Java 8 – Collectors.groupingBy Examples — Примеры использования groupingBy в Java 8.
  4. Mkyong.com: Java 8 – How to count duplicates in a List — Инструкция по подсчету дубликатов в списке с использованием Java 8.
  5. Stack Overflow: How to count the number of occurrences of an element in a List — Советы и обмен опытом на Stack Overflow.