Вы сейчас просматриваете Как пользоваться Collectors.groupingBy при работе со stream()?

Как пользоваться Collectors.groupingBy при работе со stream()?

Collectors.groupingBy — это метод, который используется для группировки элементов потока (Stream) на основе заданного критерия. Он позволяет создать Map, где ключом будет выступать значение, возвращаемое функцией группировки, а значением — коллекция элементов, которые соответствуют этому ключу. Рассмотрим принцип работы Collectors.groupingBy и его различные варианты.

Общий алгоритм работы Collectors.groupingBy

  1. Создание потока данных: Collectors.groupingBy применяется к потоку (Stream) элементов.
  2. Определение функции группировки: Сначала вы указываете функцию, которая будет определять ключи для группировки элементов.
  3. Указание коллектора для значений (необязательно): Дополнительно можно указать, как собирать значения для каждого ключа — это может быть, например, Collectors.toList() для списка или Collectors.counting() для подсчета количества элементов.
  4. Выбор типа карты (необязательно): По умолчанию используется HashMap, но можно указать другой тип карты, например, TreeMap, если нужен порядок по ключам.

Варианты использования Collectors.groupingBy

  1. Базовая группировка (по умолчанию — HashMap) В этом случае groupingBy создает карту, где каждый ключ — это результат функции группировки, а значение — список элементов, соответствующих этому ключу. Map<String, List<Programmer>> map = programmers.stream() .collect(Collectors.groupingBy(Programmer::getName));Алгоритм:
    • Для каждого программиста getName возвращает имя, которое используется как ключ.
    • Все программисты с одинаковым именем собираются в один список, который и становится значением для этого ключа.
  2. Группировка с модификацией значений (например, Collectors.counting()) Можно подсчитать количество элементов в каждой группе. Вместо List<Programmer> в значении карты будет Long, представляющий количество элементов. Map<String, Long> map = programmers.stream() .collect(Collectors.groupingBy(Programmer::getName, Collectors.counting()));Алгоритм:
    • getName по-прежнему возвращает ключ (имя программиста).
    • Вместо списка значений используется Collectors.counting(), который подсчитывает количество элементов в каждой группе и возвращает Long.
  3. Группировка с указанием типа карты По умолчанию используется HashMap, но можно указать другой тип карты, например, TreeMap или LinkedHashMap. Map<String, List<Programmer>> map = programmers.stream() .collect(Collectors.groupingBy(Programmer::getName, TreeMap::new, Collectors.toList()));Алгоритм:
    • getName возвращает имя, используемое в качестве ключа.
    • TreeMap::new указывает, что карта должна быть TreeMap, что сортирует её по ключам.
    • Collectors.toList() собирает элементы каждой группы в список.
  4. Группировка по вычисленному ключу Допустим, вы хотите сгруппировать программистов по количеству технологий, которыми они владеют. В этом случае ключом будет количество технологий, а значением — список программистов с этим количеством. Map<Integer, List<Programmer>> map = programmers.stream() .collect(Collectors.groupingBy(programmer -> programmer.getTechnologies().size()));Алгоритм:
    • Ключ — это результат programmer.getTechnologies().size() (количество технологий у программиста).
    • Программисты с одинаковым количеством технологий собираются в списки.
  5. Многоуровневая группировка Можно вложить несколько groupingBy для создания вложенной карты. Например, сгруппируем программистов по количеству технологий, а затем внутри каждой группы — по имени. Map<Integer, Map<String, List<Programmer>>> map = programmers.stream() .collect(Collectors.groupingBy( programmer -> programmer.getTechnologies().size(), // Внешний ключ — количество технологий Collectors.groupingBy(Programmer::getName) // Внутренний ключ — имя ));Алгоритм:
    • Сначала группируем программистов по количеству технологий.
    • Внутри каждой такой группы применяем еще одну группировку по имени.

Резюме

  • Collectors.groupingBy позволяет легко группировать элементы потока по определенному критерию.
  • Ключи карты определяются функцией группировки.
  • Значения можно модифицировать, применяя другие коллекторы, например, Collectors.counting(), Collectors.toSet() и т.д.
  • При необходимости можно указать тип карты или использовать многоуровневую группировку.

Надеюсь, этот алгоритм поможет вам эффективно использовать Collectors.groupingBy для разных задач!

Leonid Kleimann

I like Java!