将平面列表转换为具有每个节点深度的树结构

Convert a flat list into tree structure having the depth of each node

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

我从 React 前端收到这个 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数组,所有其他字段仅供开发人员了解节点的深度和结构(例如,Depth 包含每个父节点的索引加上当前节点的索引,均以点分隔)。

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

这些对象中的每一个都是一个 Row 对象,在前端所有的行创建一个 table。关注 Row.java 型号 class:

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
}

有人知道怎么做吗?这几天我一直在苦苦思索。

下面是执行上述任务的 sudo 代码。您可能需要处理一些极端情况。但主要思想是维护 pendingRows 的列表。对于此列表中的每一行,如果父节点已存在于 depthToRows 映射中,我们将将该行插入到父节点的子行中并从 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);
                    }
                }
            }
        }