Преобразование List в Map>

Нужно преобразовать список из слов в мэп, где ключем является первая буква слова, значением - список слов, начинающихся на указанную букву, с использованием потоков Stream API.

Пока удалось собрать только мэп, где в значениях лежит только список из одного слова, как собрать список из нескольких слов не могу понять.

List<String> wordsList = Arrays.asList(words);

Map<Character, List<String>> initialMap = wordsList.stream()
    .collect(Collectors.toMap(
        e -> e.charAt(0)
        ,t -> Collections.singletonList(t)
        ,(e1, e2) -> e1
    ));

Прошу помочь, хотя бы в какую сторону думать.


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

Автор решения: Nowhere Man

Как было отмечено в комментарии, в простейшем случае достаточно использовать Collectors.groupingBy.

Также нет необходимости строить список wordList из массива слов words, чтобы получить стрим строк, достаточно использовать Stream.of или Arrays.stream:

Map<Character, List<String>> initialMap = Arrays.stream(words)
    .collect(Collectors.groupingBy(e -> e.charAt(0)));

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

SortedMap<Character, List<String>> sortedMap = Stream.of(words)
    .collect(Collectors.groupingBy(
        e -> Character.toLowerCase(e.charAt(0)),
        TreeMap::new,
        Collectors.toList()
    ));

Ещё один вариант может использовать метод forEach, который унаследован в списке из интерфейса Iterable Iterable::forEach, и в стриме Stream::forEach.

При этом результирующая мапа будет создаваться заранее и заполняться при помощи метода Map::computeIfAbsent, чтобы создавать значения в мапе (пустые списки):

Map<Character, List<String>> map = new HashMap<>(); // или любой нужный тип

Arrays.stream(words)
// Arrays.asList(words) // допустимый вариант
      .forEach(s -> map.computeIfAbsent(s.charAt(0), k -> new ArrayList<>())
          .add(s)  // List::add - добавили элемент
      );
→ Ссылка