首页 > 解决方案 > 将平面列表转换为具有每个节点深度的树结构

问题描述

我正在使用 java,我需要将平面Set<Object>转换为一组对象,该对象可以递归地包含其他对象列表。

我从反应前端收到这个 JSON 数据:

[
    {
        name : "A",
        depth: "0",
        fullpath: "/A",
        subRows: null
    },
    {
        name : "B",
        depth: "0.0",
        fullPath: "/A/B"
        subRows: null
    },
    {
        name : "C",
        depth: "0.0.0",
        fullPath: "/A/B/C",
        subRows: null
    },
    {
        name : "D",
        depth: "1,
        fullPath: "/D",
        subRows: null
    }
]

我想将其转换为这种结构(相同的数据但具有父子关系):

[
    {
        name : "A",
        depth: "0",
        fullPath: "/A",
        subRows: [
            {
                name : "B",
                depth: "0.0",
                fullPath: "/A/B",
                subRows: [
                    {
                        name : "C",
                        depth: "0.0.0",
                        fullPath: "/A/B/C",
                        subRows: null
                    }
                ]
            }           
        ]
    }
    {
        name : "D",
        depth: "1,
        fullPath: "/D",
        subRows: null;
    }   
]

对象中最重要的字段是定义结构的subRows数组,所有其他字段仅供开发人员了解节点的深度和结构(例如,深度包含每个父节点的索引加上每个父节点的索引)当前节点,全部用点分隔)。

请不要过分依赖 fullPath,因为对象的名称不是唯一的。

这些对象中的每一个都是一个 Row 对象,在前端所有行都创建一个表。以下 Row.java 模型类:

public class Row {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;


    private String name;
    private String depth;
    private String fullPath;
    
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name="ID_PARENT")
    @JsonIgnore
    private Row parent;

    @OneToMany(mappedBy="parent", fetch = FetchType.EAGER)
    @org.hibernate.annotations.OrderBy(clause = "id")
    private Set<Row> subRows = new LinkedHashSet<Row>();
    
    public Row(){}
    
    //Getter and Setter
}

有人对如何做有想法吗?几天来我一直在用头撞它。

标签: javarecursionnested-loops

解决方案


下面是执行上述任务的 sudo 代码。您可能需要处理一些极端情况。但主要思想是维护一个pendingRows. 对于这个列表中的每一行,如果父节点已经存在于depthToRowsmap 中,我们将把该行插入到父节点的 subRows 中,并从pendingRows. 我们需要重复这个直到pendingRows是空的。

        List<Row> inRows; //input to the algo
        List<Row> pendingRows = new LinkedList<>();
        Map<String, Row> depthToRows = new HashMap<>();

        pendingRows.addAll(inRows);
        while (!pendingRows.isEmpty()){
            for(Row row: inRows){
                depthToRows.put(row.getDepth(), row);
                //find the parent depth object
                String[] arr = row.getDepth().split(".");
                if(arr.length > 1){
                    String parentDepth = String.join(".", Arrays.copyOfRange(arr, 0, arr.length - 1));
                    if(null != depthToRows.get(parentDepth)){
                        depthToRows.get(parentDepth).getSubRows().add(row);
                        pendingRows.remove(row);
                    }
                }
            }
        }


推荐阅读