Java 8 multinivel de agrupación y reduciendo

user1318369:

Tengo un escenario en el que tengo una lista de objetos de un tipo y tengo que crear una lista de otros objetos de otro tipo de la misma.

A continuación se muestra el código: Tengo una lista de empleados y necesidad de crear lista de EmployeeInfo de la primera lista. Tenga en cuenta que empleado tiene un atributo de cuenta y el EmployeeInfo tiene una lista de cuentas. En este caso, el mismo empleado puede tener varias cuentas, por lo que resulta en el EmployeeInfo lista, cada objeto de información tendrá una lista de cuentas. Así es como yo lo he hecho:

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

}

clase de prueba:

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();
}

Mientras que la pieza anterior funciona correctamente, finalmente darme una lista de EmployeeInfo, agrupados por departamento, cada uno con su lista de cuentas, quería hacerlo de manera Amore funcitonal como:

employees.stream().collect(groupingBy(Employee::getDept, groupingBy(testEmployeeGrouping::createKey, reducing(EmployeeInfo::addToList))));

La línea anterior arroja error: Incompatible tipos: T no es convertible con el empleado. Por favor alguien puede ayudarme a averiguar cómo resolver esto?

¡Gracias!

Reza Nasiri:

¿hay alguna razón por la que hizo la namede EmployeeInfofinal? si se puede cambiar que esta solución funcionará

añadir estos dos métodos a EmployeeInfo

public void setName(String name) {
    this.name = name;
}
public void AddAccount(String account) {
    this.accounts.add(account);
}

y entonces usted puede hacer esto

Collector<Employee, EmployeeInfo, EmployeeInfo> empToInfo = Collector.of(
     () -> new EmployeeInfo("", new ArrayList<String>()),
            (info, e) -> { 
                info.AddAccount(e.getAccount());
                info.setName(e.getName());
                },
     (p1,p2) -> p1.addToList(p2));

Collector<Employee, ?, Collection<EmployeeInfo>> byName = collectingAndThen(groupingBy(Employee::getName, empToInfo), 
                  (Map<String, EmployeeInfo> finisher) -> {return finisher.values();});

Map<Integer, Collection<EmployeeInfo>> r2 = employees.stream().collect(groupingBy(Employee::getDept, byName));

si se quiere mantener el inmutable EmployeeInfo, se puede utilizar en lugar de la reducción de recogida y que será como esta

Map<Integer, Collection<EmployeeInfo>> result2 = employees.stream().collect(groupingBy(Employee::getDept,
             collectingAndThen(groupingBy(Employee::getName, reducing(new EmployeeInfo("", new ArrayList<String>()), 
                                                                      empl3 -> new EmployeeInfo(empl3.getName(),Arrays.asList(empl3.getAccount())), 
                                                                      (inf1, inf2) -> inf1.addToList(inf2))), 
                                finisher -> finisher.values()))); 

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=189046&siteId=1
Recomendado
Clasificación