Java 8 multi-niveaux de regroupement et la réduction

user1318369:

J'ai un scénario où j'ai une liste d'objets d'un type et je dois créer une liste d'autres objets d'un autre type de celui-ci.

Voici le code: J'ai une liste des employés et nécessité de créer la liste des EmployeeInfo de la première liste. Notez que l'employé a un attribut de compte et le EmployeeInfo a une liste de comptes. Dans ce cas, le même employé peut avoir plusieurs comptes, donc dans la liste résultant EmployeeInfo, chaque objet d'information aura une liste des comptes. Voici comment je l'ai fait:

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

}

Classe d'essai:

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

Alors que la pièce ci-dessus fonctionne très bien, enfin me donner une liste de EmployeeInfo, regroupés par département, chacune avec sa liste des comptes, je voulais le faire de façon amore funcitonal comme:

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

La ligne ci-dessus jette erreur: Incompatible types: T ne peut être converti à l'employé. Quelqu'un peut-il me aider à comprendre comment résoudre ce problème?

Merci!

Reza Nasiri:

est - il une raison que vous avez fait la nameen EmployeeInfofinale? si vous pouvez changer que cette solution fonctionne

ajouter ces deux méthodes pour EmployeeInfo

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

et vous pouvez le faire

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 vous voulez garder l'immuable EmployeeInfo, vous pouvez utiliser la réduction à la place de la collecte et ce sera comme ça

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

Je suppose que tu aimes

Origine http://43.154.161.224:23101/article/api/json?id=189044&siteId=1
conseillé
Classement