java - Java 8 多级分组和归约
问题描述
我有一个场景,我有一个类型的对象列表,我需要从中创建另一个类型的另一个对象的列表。
下面是代码:我有一个员工列表,需要从第一个列表中创建 EmployeeInfo 列表。请注意,Employee 有一个帐户属性,而 EmployeeInfo 有一个帐户列表。在这种情况下,同一个员工可以有多个账户,因此在生成的员工信息列表中,每个信息对象都会有一个账户列表。这是我的做法:
public class Employee {
private final int dept;
private final String name;
private final String city;
private final String account;
public Employee(int dept, String name, String city, String account) {
this.dept = dept;
this.name = name;
this.city = city;
this.account = account;
}
public int getDept() {
return dept;
}
public String getName() {
return name;
}
public String getCity() {
return city;
}
public String getAccount() {
return account;
}
}
public class EmployeeInfo {
private final String name;
private final List<String> accounts;
public EmployeeInfo(String name, List<String> accounts) {
this.name = name;
this.accounts = accounts;
}
public String getName() {
return name;
}
public List<String> getAccounts() {
return accounts;
}
public EmployeeInfo addToList(EmployeeInfo employeeInfo) {
List<String> l = new ArrayList<>();
l.addAll(this.getAccounts());
l.addAll(employeeInfo.getAccounts());
return new EmployeeInfo(employeeInfo.name, l);
}
}
测试类:
public static void main(String[] args){
List<Employee> employees = new ArrayList<>();
//tradeId, secPool, datasetid, restricValue
employees.add(new Employee(1, "Mary", "Boston", "A1"));
employees.add(new Employee(1, "Mary", "Boston", "A2"));
employees.add(new Employee(1, "Alex", "NYC", ""));
employees.add(new Employee(2, "Peter", "DC", ""));
employees.add(new Employee(1, "Sophia", "DC", "A4"));
TestEmployeeGrouping testEmployeeGrouping = new TestEmployeeGrouping();
Map<Integer, List<EmployeeInfo>> result = new HashMap<>();
Map<Integer, Map<String, List<Employee>>> map = employees.stream().collect(groupingBy(Employee::getDept, groupingBy(testEmployeeGrouping::createKey)));
map.forEach((integer, stringListMap) -> {
List<EmployeeInfo> employeeInfos = createInfo(stringListMap);
result.put(integer, employeeInfos);
});
}
private static List<EmployeeInfo> createInfo(Map<String,List<Employee>> stringListMap) {
List<EmployeeInfo> employeeInfos = new ArrayList<>();
stringListMap.forEach((s, employees) -> {
List<String> accounts = employees.stream().map(Employee::getAccount).collect(Collectors.toList());
employeeInfos.add(new EmployeeInfo(employees.get(0).getName(), accounts));
});
return employeeInfos;
}
private String createKey(Employee employee) {
return employee.getDept() + employee.getName();
}
虽然上面的部分工作正常,最后给了我一个按部门分组的员工信息列表,每个都有它的帐户列表,我想以一种更实用的方式来做,比如:
employees.stream().collect(groupingBy(Employee::getDept, groupingBy(testEmployeeGrouping::createKey, reducing(EmployeeInfo::addToList))));
上面的行抛出错误:不兼容的类型:T 不能转换为 Employee。有人可以帮我弄清楚如何解决这个问题吗?
谢谢!
解决方案
这看起来有点复杂,但没有什么是不可能的
首先在 dept 上进行分组,并将 map 键命名为 dept 并将值命名为 List
其次,您需要按员工进行内部 groupBy
name
然后从内部映射中获取值并使用帐户列表转换为员工信息
Map<Integer, List<EmployeeInfo>> empInfo = employees.stream().collect(Collectors.groupingBy(Employee::getDept)).entrySet()
.stream().collect(Collectors.toMap(Map.Entry::getKey, value->value.getValue().stream().collect(Collectors.groupingBy(Employee::getName)).values()
.stream().map(emp->new EmployeeInfo(emp.stream().findFirst().get().getName(), emp.stream().map(Employee::getAccount).collect(Collectors.toList())))
.collect(Collectors.toList())));
输出
{1=[EmployeeInfo [name=Alex, accounts=[]], EmployeeInfo [name=Sophia, accounts=[A4]], EmployeeInfo [name=Mary, accounts=[A1, A2]]],
2=[EmployeeInfo [name=Peter, accounts=[]]]}
推荐阅读
- javascript - 无法通过引用传递参数 1 (Virtuemart 3.2.1) + Joomla! 3.8.11
- docker - 如何在 Docker Desktop Kubernetes 集群上找到主 IP?
- javascript - 如果
- excel - 带有可变列的 COUNTIF
- ios - 将 React Native RCTRootView 解散回 Native ViewController
- javascript - NodeJs Winston 日志行号
- c# - 如何加载表单然后阅读代码
- django - Django_filters 非模型字段的多个参数
- sql - 如何将税表合并到现有句子中
- svelte - 表单提交后重定向用户