Java - создать вложенный вид дерева из CSV-файла - PullRequest
0 голосов
/ 21 февраля 2019

Я искал похожие вопросы и не могу найти четкого решения, поэтому надеялся, что кто-нибудь сможет помочь.Я довольно новичок в Java и пытаюсь сделать следующее, но немного застрял.Проблема: у меня есть CSV-файл с тремя полями: String, int, String Это организационный список, в котором в моем отделе представлены 140 человек вместе с их менеджером, и я хочу создать вложенную древовидную структуру, отображающую всю организацию.

Поля CSV: employee, numberOfDirectReports, manager, например, образец может быть:

Bob, 5, Dave

Dave, 2, Alice

Sam, 0, Bob

, так что это говорит мне, что Алиса находится на вершине дерева, и Дейв сообщает ей,У самого Дэйва есть два прямых отчета, одним из которых является Боб.У Боба 5 прямых отчетов, одним из которых является Сэм.Сэм не имеет прямых сообщений.

Алиса

- Dave
     - DavesOtherReport

     - Bob

         - Sam

         - BobsOtherReport

         - BobsOtherReport

         - BobsOtherReport

         - BobsOtherReport

Пока что я создал класс Employee с тремя переменными: String employeeID, int numDirectReports, String manager. Я создал ArrayList с именем employeeList., который содержит 140 экземпляров сотрудников.

Я могу распечатать список сотрудников и их менеджера.Но то, что я хочу сделать, это перебрать список / массив (извиняюсь, если я немного смешиваю свою терминологию) и создать что-то вроде вышеупомянутой древовидной структуры для всего населения.

Есть идеи?Нужно ли для этого создать еще одну промежуточную структуру данных?если так, как я могу инициализировать, а затем заполнить его?Или я могу напечатать вид дерева, которое я использую после использования только списка employeeList, который я уже заполнил?

Ответы [ 2 ]

0 голосов
/ 21 февраля 2019

Так что, если я вас правильно понимаю, у вас будет такой класс:

public class Employee {
    private String employeeID;
    private String manager;
    int numDirectReports;
    private List<Employee> employeeList;

...
}

Несколько комментариев:

  • Почему бы не объявить manager как Employee?не будет ли проще использовать?
  • поле numDirectReports является избыточным: его значение должно быть равно employeeList.size().
  • Один и тот же сотрудник не должен появляться дважды в employeeListнекоторого менеджера.

Поэтому я бы лучше объявил класс следующим образом:

public class Employee {
    private String employeeID;
    private Employee manager;
    private final Set<Employee> employeeSet = new HashSet<>();

    public String getEmployeeID() {
        return employeeID;
    }

    public void setEmployeeID(String employeeID) {
        this.employeeID = employeeID;
    }

    public Employee getManager() {
        return manager;
    }

    public void setManager(Employee manager) {
        this.manager = manager;
    }

    public Set<Employee> getEmployeeSet() {
        return new HashSet<>(employeeSet);
    }

    public void addEmployee(Employee e) {
        employeeSet.add(e);
    }
}

Теперь, чтобы загрузить CSV при сборке дерева одновременно, я бы использовалa Map<String,Employee>:

    Map<String,Employee> allEmployees = new HashMap<>();
    for (String[] record: csvRecords()) {
        String id = record[0];
        int redundant = Integer.parseInt(record[1]);
        String managerId = record[2];
        Employee emp = allEmployees.get(id);
        if (emp == null) {
            emp = new Employee();
            emp.setEmployeeID(id);
            allEmployees.put(id, emp);
        }
        Employee manager = null;
        if (managerId != null && managerId.length() > 0) {
            manager = allEmployees.get(managerId);
            if (manager == null) {
                manager = new Employee();
                manager.setEmployeeID(managerId);
                allEmployees.put(managerId, manager);
            }
            manager.addEmployee(emp);
        }
        emp.setManager(manager);
    }

ОБНОВЛЕНИЕ

Если вам нужно количество прямых отчетов, вы можете добавить метод:

public int numberOfDirectReports() {
    return employeeSet.size();
}
0 голосов
/ 21 февраля 2019

Вам нужно обновить каждого сотрудника, чтобы добавить в него список сотрудников, который находится непосредственно под ним.(Я занят написанием кода, чтобы объяснить это:))

public static class Employee{
        String name;
        int numberOfDirectReport;
        String manager;
        List<Employee> directReport;

        public Employee(String name, int numberOfDirectReport, String manager) {
            this.name = name;
            this.numberOfDirectReport = numberOfDirectReport;
            this.manager = manager;
            this.directReport = new ArrayList<>();
        }

        public boolean add(Employee employee) {
            return directReport.add(employee);
        }

        public String toString(){
            return toString("");
        }

        public String toString(String prefix){
            String result = prefix + name + "\n";
            for(Employee child : directReport){
                result += child.toString(prefix+"\t");
            }
            return result;
        }
    }

    public static void main(String[] args) {
        // step 1: loading employees, to be replace by actual call to CSV reader
        HashMap<String, Employee> employees = new HashMap<>();
        employees.put("Bob", new Employee("Bob", 5, "Dave"));
        employees.put("Dave", new Employee("Dave", 2, "Alice"));
        employees.put("Sam", new Employee("Sam", 0, "Bob"));
        employees.put("Alice", new Employee("Alice", 2, null));

        // step 1.2: adding fake employees for test completion
        for(int i = 0; i < 4; i++){
            String name = "BobOtherReport"+i;
            employees.put(name, new Employee(name, 0, "Bob"));
        }
        employees.put("DaveOtherReport", new Employee("DaveOtherReport", 0, "Dave"));

        // step 2: link employees together
        for(Employee employee : employees.values()){
            if(employee.manager != null){
                // we retrieve the manager from the map and add this employee in the list inside it
                employees.get(employee.manager).add(employee);
            }
        }

        // step 3: display the top one. Either you loop on the map to find the one without manager, either you specify it
        System.out.println(employees.get("Alice").toString());
    }

, который дал вывод

Alice
    Dave
        Bob
            BobOtherReport0
            BobOtherReport2
            BobOtherReport1
            BobOtherReport3
            Sam
        DaveOtherReport

Шаг 2 можно обновить, чтобы проверить, что менеджер известен, прежде чем добавить ссылкучтобы избежать NPE.Другим решением было бы создать менеджера на лету и добавить его на карту в этом же фрагменте.

if(employee.manager != null){
                // we retrieve the manager from the map and add this employee in the list inside it
                Employee manager = employees.get(employee.manager);
                if(manager != null){
                    // manager has been loaded before
                    manager.add(employee);
                }
            }
...