Как конвертировать список в карту карты Карта> - PullRequest
2 голосов
/ 17 октября 2019

У меня есть List<Employee> e, который я хочу преобразовать в Map<String, Map<String,Emp>>, где внешняя строка должна быть «Имя», а внутренняя строка должна быть «Домен».

       Name Id Domain
e(0) - Emp1, 1, Insurance
e(1) - Emp1, 2, Sales
e(2) - Emp2, 3, Sales
e(3) - Emp4, 4, Marketing

Я пыталсяследующее -

e.stream().collect(Collectors.groupingBy(
                                   Employee::getName,
                                   toMap(Employee::getDomain,Emp)));

Таким образом, ожидаемая карта вывода должна выглядеть так:

<Emp1>
     <Insurance, e(0)>
     <Sales, e(1)>
<Emp2>
     <Sales, e(2)>
<Emp4>
     <Marketing, e(3)>

Но я получаю только уникальные значения, фактический результат -

<Emp1>
     <Insurance, e(0)>
<Emp2>
     <Sales, e(2)>
<Emp4>
     <Marketing, e(3)>

Может кто-тоскажите лучший способ сделать это?

Ответы [ 2 ]

1 голос
/ 17 октября 2019

В основном вам нужна вложенная группировка, такая как:

Map<String, Map<String, List<Employee>>> groupedMap = employees.stream()
        .collect(Collectors.groupingBy(Employee::getName,
                Collectors.groupingBy(Employee::getDomain, Collectors.toList())));

Примечание - значения List<Employee> - это сотрудники, сгруппированные по имени, а затем по домену. (Оба одинаково объединены в Список.)


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

Map<String, Map<String, Employee>> groupedReducedMap = employees.stream()
        .collect(Collectors.groupingBy(Employee::getName,
                Collectors.toMap(Employee::getDomain,
                        Function.identity(), // value as the employee instance
                        (a, b) -> a))); // choose first instance for similar 'domain'
0 голосов
/ 17 октября 2019

Поскольку выходные данные должны быть Map<String, Map<String,Employee>>, а не Map<String, Map<String,List<Employee>>> (т. Е. На основе запрошенного вывода не может быть двух Employee с одинаковыми именами и одинаковым доменом), вы можете связать два groupingBy изатем используйте reducing, чтобы каждая внутренняя группа имела один Employee вместо List<Employee>:

Map<String, Map<String,Optional<Employee>>> output =
    e.stream()
     .collect(Collectors.groupingBy(Employee::getName,
                                    Collectors.groupingBy(Employee::getDomain,
                                                          Collectors.reducing((x1,x2)->x2))));

Проблема с этой версией reducing состоит в том, что она возвращает Optional<Employee> вместо Employee, хотя мы знаем, что Optional никогда не будет пустым.

Мы можем обойти это с помощью:

  Map<String, Map<String,Employee>> output =
      e.stream()
       .collect(Collectors.groupingBy(Employee::getName,
                                      Collectors.groupingBy(Employee::getDomain,
                                                            Collectors.reducing(e.get(0),
                                                                                (x1,x2)->x2))));

Теперь мы используем вариант reducing имеет значение идентификатора, которому мы передаем произвольный Employee экземпляр (неважно, какой, поскольку он всегда будет заменен правильным экземпляром).

...