Skip to content
Advertisement

Flat tree of objects while keeping father and child

I have a class Employee which has a tree structure with property team

public class Employee {

    private String name;
    private List<Employee> team;
}

Using Java lambdas I need to flat this tree into same level list while converting Employee class into the following ConvertedEmployee while storing names in dedicated lead and subordinates properties. So ConvertedEmployee is in some sense a node which keeps parent and children. And I need to have a list of those.

    public class ConvertedEmployee {

    private String name;
    private String lead;
    private List<String> subordinatesNames;
}

So final result should be List<ConvertedEmployee>

I was thinking to use recursion here.

But I can only flat the tree and can’t rebuild it’s parents.

EDIT: Input is instance of Employee object that basically has a tree inside team

Advertisement

Answer

A non-recursive solution using concatenation of the streams followed by filtering out the “duplicated” entries which do not have lead field set:

public static List<ConvertedEmployee> convert(List<Employee> staff) {
    return staff
        .stream()
        .flatMap(e -> Stream.concat(
            // subordinates of current employee
            e.getTeam()
             .stream()
             .map(sub -> new ConvertedEmployee(
                 sub.getName(), e.getName(),
                 sub.getTeam().stream().map(Employee::getName).collect(Collectors.toList())
             )),
            // current employee by themself
            Stream.of(new ConvertedEmployee(
                 e.getName(), null,
                 e.getTeam().stream().map(Employee::getName).collect(Collectors.toList())
            ))
        ))
        .collect(Collectors.collectingAndThen(
            Collectors.toMap(
                ConvertedEmployee::getName,
                c -> c,
                (e1, e2) -> e1.getLead() != null ? e1 : e2.getLead() != null ? e2 : e1,
                LinkedHashMap::new
            ),
            map -> new ArrayList<>(map.values())
        ));
}

Test for the following setup:

Employee intern = new Employee("intern", Collections.emptyList());
Employee junior = new Employee("junior", Collections.emptyList());
Employee middleDev = new Employee("mid", Arrays.asList(junior));
Employee devOps = new Employee("devOps", Collections.emptyList());
Employee teamLead = new Employee("teamLead", Arrays.asList(intern, middleDev));
Employee pm = new Employee("mgr", Arrays.asList(teamLead, devOps));

List<Employee> staff = Arrays.asList(intern, junior, middleDev, devOps, teamLead, pm);

convert(staff).forEach(System.out::println);

Output:

ConvertedEmployee(name=intern, lead=teamLead, subordinatesNames=[])
ConvertedEmployee(name=junior, lead=mid, subordinatesNames=[])
ConvertedEmployee(name=mid, lead=teamLead, subordinatesNames=[junior])
ConvertedEmployee(name=devOps, lead=mgr, subordinatesNames=[])
ConvertedEmployee(name=teamLead, lead=mgr, subordinatesNames=[intern, mid])
ConvertedEmployee(name=mgr, lead=null, subordinatesNames=[teamLead, devOps])
3 People found this is helpful
Advertisement