当前位置: 代码迷 >> java >> Java-从CSV文件创建嵌套树视图
  详细解决方案

Java-从CSV文件创建嵌套树视图

热度:99   发布时间:2023-07-17 20:12:31.0

我已经搜索了类似的问题,但找不到明确的解决方案,因此希望有人能提供帮助。 我刚接触Java并尝试执行以下操作,但是有点卡住了。 问题:我有一个包含三个字段的CSV文件:String,int,String这是一个组织列表,其中显示了我部门中的140个人以及他们的经理,并且我想创建一个嵌套的树结构来显示整个组织。

CSV字段是:员工,numberOfDirectReports,经理,例如,一个示例可能是:

Bob, 5, Dave

Dave, 2, Alice

Sam, 0, Bob

所以这告诉我爱丽丝在树顶上,戴夫向她报告。 戴夫本人有2个直接报告,其中之一是鲍勃。 鲍勃有5个直接举报,其中之一是山姆。 Sam没有直接报道。

爱丽丝

- Dave
     - DavesOtherReport

     - Bob

         - Sam

         - BobsOtherReport

         - BobsOtherReport

         - BobsOtherReport

         - BobsOtherReport

到目前为止,我所做的是创建一个名为Employee的类,其中包含三个变量String employeeID,int numDirectReports,String manager我创建了一个名为employeeList的ArrayList,其中包含140个Employee实例。

我可以打印出雇员及其经理的名单。 但是我想做的是遍历列表/数组(如果我有点混用我的术语,很抱歉),并为整个人群产生类似于上述树形结构的内容。

有任何想法吗? 我是否需要为此创建另一个中间数据结构? 如果是这样,如何初始化然后填充它? 或者仅使用已经填充的employeeList之后,我是否可以打印我所用的树形?

您需要更新每个员工,以便在其中添加直接在其下方的员工列表。 (我正忙着编写代码来解释它:)

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

在添加链接以避免NPE之前,可以更新步骤2以检查管理器是否已知。 另一个解决方案是即时创建管理器,并将其添加到同一片段中的地图中。

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

因此,如果我对您的理解正确,那么您将拥有这样的课程:

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

...
}

一些评论:

  • 为什么不宣布managerEmployee 使用起来会不会更简单?
  • 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,我将使用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();
}
  相关解决方案