首页 > 解决方案 > 从 Java Hashmap 生成树结构

问题描述

我目前有一个具有多个属性的类,这些属性描述了我系统中某种类型的对象。这个类被称为EnrollmentInfo.

我还有一个结构如下的哈希图;

HashMap<EnrolmentInfo, List<EnrolmentInfo>> devices = new HashMap<>();

可以看出,这个 hashmap 中的 value 属性包含一个 EnrollmentInfo 类类型的 ArrayList。为了提供一些上下文,此哈希图用于将树结构的父节点和关联的子节点保存为键值对。

我通过遍历并从子/父表中提取详细信息来生成此哈希图,如下所示:

Child : Parent
    1 : 0
    2 : 0
    3 : 2
    4 : 0
    5 : 4
    6 : 4
    7 : 1
    8 : 6

提取父母和孩子并放入HashMap的代码如下:

        // Extracts the parents and assigns them to the key values
        for (EnrolmentInfo enrolmentInfo : enrolmentInfos) {
            Integer nodeParentId = enrolmentInfo.getParentId();
            EnrolmentInfo parentEnrolmentInfo = dms.getDevice(nodeParentId).getEnrolmentInfo();
            devices.put(parentEnrolmentInfo, new ArrayList<EnrolmentInfo>());
        }
        // Extracts the children and assigns them to the children arraylist of each associated parent.
        for (EnrolmentInfo enrolmentInfo : enrolmentInfos) {
            int nodeId = enrolmentInfo.getId();
            Integer parentId = enrolmentInfo.getParentId();
            EnrolmentInfo nodeEnrolmentInfo = dms.getDevice(nodeId).getEnrolmentInfo();
            for (Map.Entry<EnrolmentInfo, List<EnrolmentInfo>> parentDevice : devices.entrySet()) {
                if (parentDevice.getKey().getId() == parentId) {
                    parentDevice.getValue().add(nodeEnrolmentInfo);
                    break;
                }
            }
        }

我现在的问题是将这个 hashmap 组合成一个实际的树结构,以便它可以通过 JSON 库编译成人类可读的形式。

更具体地说,如何根据上面提到的 HashMap 生成嵌套树结构?

编辑:下面显示的是我最后期望的那种 JSON 格式的示例结构。

{
    "id" : 0,
    "children" : [
        {
            "id" : 1,
            "children" : [
                {
                    "id" : 7,
                    "children" : []
                }
            ]
        },
        {
            "id" : 2,
            "children" : [
                {
                    "id" : 3,
                    "children" : []
                }
            ]
        },
        {
            "id" : 4,
            "children" : [
                {
                    "id" : 5,
                    "children" : []
                },
                {
                    "id" : 6,
                    "children" : [
                        {
                            "id" : 8,
                            "children" : []
                        }
                    ]
                }
            ]
        }
    ]
}

编辑:到目前为止,我已经创建了一个 bean 类,如下所示:

public class DeviceHierarchyNode implements Serializable {
@ApiModelProperty(name = "id", value = "ID of the node generated. Same as Device ID",
        required = true)
private int id;

@ApiModelProperty(name = "label", value = "Device name as suggested by the user.",
        required = true)
private String label;

@ApiModelProperty(name = "children", value = "List of child devices associated with device if any",
        required = true)
private List<DeviceHierarchyNode> children;

我的计划是使用它来创建最终的嵌套结构。

标签: javajsontreehashmapparent-child

解决方案


警告:hacky。

您能否创建一个包装底层的节点类型:

public class EnrolmentInfoNode {
    private EnrolmentInfo info;
    private List<EnrolmentInfoNode> children;

    public EnrolmentInfoNode(EnrolmentInfo contents) {
        this.info = contents;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + info.getId();
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        EnrolmentInfoNode other = (EnrolmentInfoNode) obj;
        if (info.getId() != other.info.getId())
            return false;
        return true;
    }

    public void addChild(EnrolmentInfoNode child) {
        if (children == null) {
            children = new ArrayList<>();
        }

        children.add(child);
    }
}

然后重新映射:

    Map<EnrolmentInfo, EnrolmentInfoNode> nodeMap = new HashMap<>();

    for (Entry<EnrolmentInfo, List<EnrolmentInfo>> entry : map.entrySet()) {
        for (EnrolmentInfo child : entry.getValue()) {
            EnrolmentInfoNode childNode = nodeMap.computeIfAbsent(child, EnrolmentInfoNode::new);

            nodeMap.computeIfAbsent(entry.getKey(), EnrolmentInfoNode::new)
                   .addChild(childNode);
        }
    }

假设您知道节点 0 是父节点:

    String json = new GsonBuilder().setPrettyPrinting()
                                   .create()
                                   .toJson(nodeMap.get(enrolmentInfo0));

    System.out.println(json);

如果不这样做,您可以向 中添加“parentNode”字段EnrolmentInfoNode,然后扫描节点映射以找到第一个具有空父节点(因此是根节点)的节点,然后您就可以参加比赛了。


推荐阅读