如何将列表转换为 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
实例传递给它(哪个并不重要,因为它总是被正确实例)。
我有一个 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
实例传递给它(哪个并不重要,因为它总是被正确实例)。