如何将列表转换为 Map 的 Map<String, Map<String,Object>>

How to Convert a List Into Map of Map Map<String, Map<String,Object>>

我有一个 List<Employee> e,我想将其转换成 Map<String, Map<String,Emp>> 其中外部字符串应为 "Name",内部字符串应为 "Domain".

       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)>

有人能告诉我最好的方法吗?

您主要寻找的是嵌套分组,例如:

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'

由于输出应该是 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 的问题在于它 returns 是 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 实例传递给它(哪个并不重要,因为它总是被正确实例)。