从包含部门列表的员工对象制作部门到员工列表的映射
Make a map of Department to List of employee from employee object containing list of departments
问题:员工包含部门列表,我们现在有一个员工列表如何从员工列表中获取像 Map 这样的地图。
下面的代码可以解决问题,但我想知道如何有效地使用流 api 而不是 for 循环。
Department a = new Department("a");
Department b = new Department("b");
Department c = new Department("c");
Employee e1 = new Employee("e1", List.of(a, b));
Employee e2 = new Employee("e2", List.of(c, b));
Employee e3 = new Employee("e3", List.of(c, a));
Employee e4 = new Employee("e4", List.of(a, b, c));
List<Employee> employees = List.of(e1, e2, e3, e4);
Set<Department> departments = employees.stream().flatMap(employee ->
employee.getDepartments().stream()).collect(Collectors.toSet());
for (Department d : departments) {
for (Employee employee : employees) {
if (employee.getDepartments().contains(d)) {
if (!result.containsKey(d)) {
result.put(d, new ArrayList<Employee>());
}
result.get(d).add(employee);
}
}
}
return result;
抱歉,在移动设备上。目前无法添加示例代码
- 流式传输所有员工
- 平面映射到配对 (Apache) 或映射条目(JDK 抽象映射简单不可变条目)
- 收藏到地图。键映射是部门,值映射。这是通过按部门分组,将员工存储为列表来完成的(参见相关问题:https://whosebug.com/a/49889657/1870799)
您可以按照以下方式进行:
Map<Department, List<Employee>> map =
departments.stream()
.collect(Collectors.toMap(
Function.identity(),
d -> employees.stream()
.filter(e -> e.getDepartments().contains(d))
.collect(Collectors.toList())
)
);
即使没有任何 stream-magic 也可能值得一提的是,你只需要一个循环对,超过你已经拥有的(员工和他们的部门):
[...]
List<Employee> employees = List.of(e1, e2, e3, e4);
for (Employee employee : employees) {
for (Department d : employee.getDepartments()) {
if (!result.containsKey(d)) {
result.put(d, new ArrayList<Employee>());
}
result.get(d).add(employee);
}
}
return result;
然后你可以尝试一些 stream-flatmap-groupingby magic:
[...]
List<Employee> employees = List.of(e1, e2, e3, e4);
var result = employees.stream().flatMap(employee->employee.getDepartments().stream()
.map(department->AbstractMap.SimpleImmutableEntry<>(department,employee))
.collect(Collectors.groupingBy(pair->pair.getKey()));
这里的缺点是 result
将成为 Map<Department,AbstractMap.SimpleImmutableEntry<Department,Employee>
。 (AbstractMap.SimpleImmutableEntry
是一个 2 元素的元组,只是它的名字很长)。
上面的片段可能有错别字,实际上我只是运行你的任务使用Map<String,List<String>>
作为员工部门的东西,因为我不想写补充类:
public static void main(String[] args) {
var a="a";
var b="b";
var c="c";
var empdep=new HashMap<String, List<String>>();
empdep.put("e1", List.of(a, b));
empdep.put("e2", List.of(c, b));
empdep.put("e3", List.of(c, a));
empdep.put("e4", List.of(a, b, c));
System.out.println(empdep);
var depemp=new HashMap<String, List<String>>();
for(var employee:empdep.entrySet())
for(var department:employee.getValue()) {
if(!depemp.containsKey(department))
depemp.put(department, new ArrayList<String>());
depemp.get(department).add(employee.getKey());
}
System.out.println(depemp);
System.out.println(
empdep.entrySet().stream().flatMap(employee->employee.getValue().stream()
.map(department->new AbstractMap.SimpleImmutableEntry<>(department, employee.getKey())))
.collect(Collectors.groupingBy(pair->pair.getKey()))
);
}
此代码输出
{e1=[a, b], e2=[c, b], e3=[c, a], e4=[a, b, c]}
{a=[e1, e3, e4], b=[e1, e2, e4], c=[e2, e3, e4]}
{a=[a=e1, a=e3, a=e4], b=[b=e1, b=e2, b=e4], c=[c=e2, c=e3, c=e4]}
其中第一行是输入“列表”(这里只是一个映射,但是遍历它的 entrySet()
与列表是一样的),第二行是 for 的结果-循环对,生成所需的地图,第三行是流魔法的结果,但带有部门“内部”的部门-员工对列表。
那是昨天,今天就是今天。我对 groupingBy()
和 mapping()
有了更多的了解。这条“线”
System.out.println(
empdep.entrySet().stream().flatMap(employee->employee.getValue().stream()
.map(department->new AbstractMap.SimpleImmutableEntry<>(department, employee.getKey())))
.collect(Collectors.groupingBy(pair->pair.getKey(),Collectors.mapping(pair->pair.getValue(), Collectors.toList()))));
使用前面的字符串-字符串示例生成所需的输出,
{a=[e1, e3, e4], b=[e1, e2, e4], c=[e2, e3, e4]}
然后是完整代码,Employee
和 Department
类:
public class Test {
public static void main(String[] args) {
Department a = new Department("a");
Department b = new Department("b");
Department c = new Department("c");
Employee e1 = new Employee("e1", List.of(a, b));
Employee e2 = new Employee("e2", List.of(c, b));
Employee e3 = new Employee("e3", List.of(c, a));
Employee e4 = new Employee("e4", List.of(a, b, c));
List<Employee> employees = List.of(e1, e2, e3, e4);
Map<Department,List<Employee>> result=employees.stream()
.flatMap(employee->employee.getDepartments().stream()
.map(department->new Pair(department,employee)))
.collect(Collectors.groupingBy(pair->pair.d,
Collectors.mapping(pair->pair.e,
Collectors.toList())));
System.out.println(result);
}
static class Department{final String name;Department(String name){this.name=name;}public String toString(){return name;}}
static class Employee{final String name;final List<Department> departments;Employee(String name,List<Department> departments){this.name=name;this.departments=departments;}List<Department> getDepartments(){return departments;}public String toString() {return name;}}
// this is just a helper class instead of AbstractMap.whatever
static class Pair{final Department d;final Employee e;Pair(Department d,Employee e){this.d=d;this.e=e;}}
}
此代码生成所需的 Map<Department,List<Employee>> result
,并打印
{b=[e1, e2, e4], a=[e1, e3, e4], c=[e2, e3, e4]}
也在 IdeOne
问题:员工包含部门列表,我们现在有一个员工列表如何从员工列表中获取像 Map
下面的代码可以解决问题,但我想知道如何有效地使用流 api 而不是 for 循环。
Department a = new Department("a");
Department b = new Department("b");
Department c = new Department("c");
Employee e1 = new Employee("e1", List.of(a, b));
Employee e2 = new Employee("e2", List.of(c, b));
Employee e3 = new Employee("e3", List.of(c, a));
Employee e4 = new Employee("e4", List.of(a, b, c));
List<Employee> employees = List.of(e1, e2, e3, e4);
Set<Department> departments = employees.stream().flatMap(employee ->
employee.getDepartments().stream()).collect(Collectors.toSet());
for (Department d : departments) {
for (Employee employee : employees) {
if (employee.getDepartments().contains(d)) {
if (!result.containsKey(d)) {
result.put(d, new ArrayList<Employee>());
}
result.get(d).add(employee);
}
}
}
return result;
抱歉,在移动设备上。目前无法添加示例代码
- 流式传输所有员工
- 平面映射到配对 (Apache) 或映射条目(JDK 抽象映射简单不可变条目)
- 收藏到地图。键映射是部门,值映射。这是通过按部门分组,将员工存储为列表来完成的(参见相关问题:https://whosebug.com/a/49889657/1870799)
您可以按照以下方式进行:
Map<Department, List<Employee>> map =
departments.stream()
.collect(Collectors.toMap(
Function.identity(),
d -> employees.stream()
.filter(e -> e.getDepartments().contains(d))
.collect(Collectors.toList())
)
);
即使没有任何 stream-magic 也可能值得一提的是,你只需要一个循环对,超过你已经拥有的(员工和他们的部门):
[...]
List<Employee> employees = List.of(e1, e2, e3, e4);
for (Employee employee : employees) {
for (Department d : employee.getDepartments()) {
if (!result.containsKey(d)) {
result.put(d, new ArrayList<Employee>());
}
result.get(d).add(employee);
}
}
return result;
然后你可以尝试一些 stream-flatmap-groupingby magic:
[...]
List<Employee> employees = List.of(e1, e2, e3, e4);
var result = employees.stream().flatMap(employee->employee.getDepartments().stream()
.map(department->AbstractMap.SimpleImmutableEntry<>(department,employee))
.collect(Collectors.groupingBy(pair->pair.getKey()));
这里的缺点是 result
将成为 Map<Department,AbstractMap.SimpleImmutableEntry<Department,Employee>
。 (AbstractMap.SimpleImmutableEntry
是一个 2 元素的元组,只是它的名字很长)。
上面的片段可能有错别字,实际上我只是运行你的任务使用Map<String,List<String>>
作为员工部门的东西,因为我不想写补充类:
public static void main(String[] args) {
var a="a";
var b="b";
var c="c";
var empdep=new HashMap<String, List<String>>();
empdep.put("e1", List.of(a, b));
empdep.put("e2", List.of(c, b));
empdep.put("e3", List.of(c, a));
empdep.put("e4", List.of(a, b, c));
System.out.println(empdep);
var depemp=new HashMap<String, List<String>>();
for(var employee:empdep.entrySet())
for(var department:employee.getValue()) {
if(!depemp.containsKey(department))
depemp.put(department, new ArrayList<String>());
depemp.get(department).add(employee.getKey());
}
System.out.println(depemp);
System.out.println(
empdep.entrySet().stream().flatMap(employee->employee.getValue().stream()
.map(department->new AbstractMap.SimpleImmutableEntry<>(department, employee.getKey())))
.collect(Collectors.groupingBy(pair->pair.getKey()))
);
}
此代码输出
{e1=[a, b], e2=[c, b], e3=[c, a], e4=[a, b, c]} {a=[e1, e3, e4], b=[e1, e2, e4], c=[e2, e3, e4]} {a=[a=e1, a=e3, a=e4], b=[b=e1, b=e2, b=e4], c=[c=e2, c=e3, c=e4]}
其中第一行是输入“列表”(这里只是一个映射,但是遍历它的 entrySet()
与列表是一样的),第二行是 for 的结果-循环对,生成所需的地图,第三行是流魔法的结果,但带有部门“内部”的部门-员工对列表。
那是昨天,今天就是今天。我对 groupingBy()
和 mapping()
有了更多的了解。这条“线”
System.out.println(
empdep.entrySet().stream().flatMap(employee->employee.getValue().stream()
.map(department->new AbstractMap.SimpleImmutableEntry<>(department, employee.getKey())))
.collect(Collectors.groupingBy(pair->pair.getKey(),Collectors.mapping(pair->pair.getValue(), Collectors.toList()))));
使用前面的字符串-字符串示例生成所需的输出,
{a=[e1, e3, e4], b=[e1, e2, e4], c=[e2, e3, e4]}
然后是完整代码,Employee
和 Department
类:
public class Test {
public static void main(String[] args) {
Department a = new Department("a");
Department b = new Department("b");
Department c = new Department("c");
Employee e1 = new Employee("e1", List.of(a, b));
Employee e2 = new Employee("e2", List.of(c, b));
Employee e3 = new Employee("e3", List.of(c, a));
Employee e4 = new Employee("e4", List.of(a, b, c));
List<Employee> employees = List.of(e1, e2, e3, e4);
Map<Department,List<Employee>> result=employees.stream()
.flatMap(employee->employee.getDepartments().stream()
.map(department->new Pair(department,employee)))
.collect(Collectors.groupingBy(pair->pair.d,
Collectors.mapping(pair->pair.e,
Collectors.toList())));
System.out.println(result);
}
static class Department{final String name;Department(String name){this.name=name;}public String toString(){return name;}}
static class Employee{final String name;final List<Department> departments;Employee(String name,List<Department> departments){this.name=name;this.departments=departments;}List<Department> getDepartments(){return departments;}public String toString() {return name;}}
// this is just a helper class instead of AbstractMap.whatever
static class Pair{final Department d;final Employee e;Pair(Department d,Employee e){this.d=d;this.e=e;}}
}
此代码生成所需的 Map<Department,List<Employee>> result
,并打印
{b=[e1, e2, e4], a=[e1, e3, e4], c=[e2, e3, e4]}
也在 IdeOne