【问题标题】:Deeply nested hashmaps in JavaJava中深度嵌套的哈希图
【发布时间】:2019-12-12 12:22:24
【问题描述】:

我用这个例子来 Accessing Deeply nested HashMaps in Java 构建数据结构来存储节点名称和属性。

这是更新后的代码:

class NestedMap {

private final HashMap<String, NestedMap> child;

private Map<String, Object> value = new HashMap<>();

public NestedMap() {
    child = new HashMap<>();
    setValue(null);
}

public boolean hasChild(String k) {
    return this.child.containsKey(k);
}

public NestedMap getChild(String k) {
    return this.child.get(k);
}

public void makeChild(String k) {
    this.child.put(k, new NestedMap());
}

public Map<String, Object> getValue() {
    return value;
}

public void setValue(Map<String, Object> value) {
    this.value = value;
}

}

还有我的用法示例:

    class NestedMapIllustration {
        public static void main(String[] args) {

        NestedMap m = new NestedMap();

        m.makeChild("de");
        m.getChild("de").makeChild("content");
        m.getChild("de").getChild("content").makeChild("00");
        m.getChild("de").getChild("content").makeChild("0");
        m.getChild("de").getChild("content").makeChild("1");
        m.getChild("de").getChild("content").makeChild("01");
        m.getChild("de").getChild("content").getChild("01").makeChild("fieldsets");
        m.getChild("de").getChild("content").getChild("01").getChild("fieldsets").makeChild("0");
        m.getChild("de").getChild("content").getChild("01").getChild("fieldsets").getChild("0").makeChild("fields");
        m.getChild("de").getChild("content").getChild("01").getChild("fieldsets").getChild("0").getChild("fields").makeChild("0");
        Map<String, Object> properties = new HashMap<>();
        properties.put("key", "value");
        properties.put("key2", "value");
        m.getChild("de").getChild("content").getChild("01").getChild("fieldsets").getChild("0").getChild("fields").setValue(properties);
}

我不想为每个值创建一个新对象,而是始终创建一个 new HashMap,我可以在其中存储节点属性。

我通过访问 JCR 数据存储中的节点并提取它们的值和属性来接收我的数据结构。这就是我生成的数据结构在输出 yaml 文件中的外观:

我怎样才能更有效地做到这一点?

【问题讨论】:

  • 为什么不采用像 JSON 这样的行业标准呢?
  • 我认为我需要为snakeyaml转储(bitbucket.org/asomov/snakeyaml/wiki/…)构建一个映射结构。
  • 你不需要map结构,它只是作为一个例子(比如List&lt;Integer&gt;)。如果你已经有了类结构,你应该可以直接序列化它。即使你想要一个特定的结构,我也建议不要创建你自己的机制。
  • 我确实有类结构,但据我了解,我需要先将其存储在内存中的对象中,然后才能使用snakeyaml 转储它。这就是为什么我试图将它存储在嵌套的地图结构中。不好意思,我不明白你说的直接序列化是什么意思?
  • 因此您实际上不需要嵌套地图,您需要将一些数据转储为 YAML。现在你要找到问题的根源了。我建议阅读snakeyaml 文档以了解如何分段编写文件,您只是在浪费时间尝试先将内容转换为地图。

标签: java hashmap snakeyaml


【解决方案1】:

您已经竭尽全力让您使用任何键,但您使用的是字符串键,即使其中一个键是 "01",这表明它是一个数字。

我可以由此得出结论,键总是字符串吗?

在这种情况下,为什么不定义一个分隔符,比如斜线,并使用一个普通的旧TreeMap&lt;String, V&gt;?然后你可以这样做:

m.put("de/content/01/fieldsets/0/fields", properties);

如果你想要de/content/01“树”中的所有内容,你可以这样做:

m.subMap("de/content/01/", "de/content/010");

以上将为您提供一个包含 de/content/01 的每个子项的地图。 0010 的末尾有'magic':零是ascii 表中斜线之后的下一个字符。

如果您希望任何给定的键映射到任意数量的值,您可以使用:

TreeMap<String, List<V>> map = new TreeMap<>();

把东西放进去:

map.computeIfAbsent(key, k -> new ArrayList<>()).add(elem);

把事情弄出来:

for (V value : map.getOrDefault(key, List.of())) {
    // works even if key isn't in there (loops 0 times then)
}

【讨论】:

  • 是的,键是一个字符串。我更新了我的代码,删除了你建议的泛型。我不确定如何使用您建议的 TreeMap 结构。我需要保留节点的层次结构(即知道谁是父节点)。
  • 层次结构是排序固有的:TreeMaps 是固有排序的。这就是这里的诀窍。要找到父母,只需扫描最后一个斜线并删除直到那时的所有文本。
【解决方案2】:

使用递归解决问题

public HashMap<String,Object> nestedMap(Node node) {

           HashMap<String, Object> map = new LinkedHashMap<>();

           PropertyIterator pi;
            try {
                pi = node.getProperties();
                //Get properties for the root node
                   while(pi.hasNext())
                    {
                       Property p = pi.nextProperty();
                       String name = p.getName();
                       String val = p.getString();

                       map.put(name,val);

                    }//end of while for properties of root node
            } catch (RepositoryException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }


           Iterable<Node> children;
            try {
                children = NodeUtil.getNodes(node);
                for (Node child : children) {

                    if (!child.getPrimaryNodeType().getName().contains("mgnl:page")) {  
                      map.put (child.getName(), nestedMap(child));

                   }//end of checking if PrimaryNodeType is of type mgnl:page
                }

            } catch (RepositoryException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            return map;
        }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-10-31
    • 1970-01-01
    • 2017-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-21
    相关资源
    最近更新 更多