【问题标题】:Convert map to nested map将地图转换为嵌套地图
【发布时间】:2021-06-15 15:15:58
【问题描述】:

我的 YamlFile 类上有这个映射,它以这种格式存储文件的所有键:String key = "firskey.secondkey.thirdkey", Object value = "Example value"

  private static Map<String, Object> deepkeymap;

现在,我想将我的 deepkeymap 转换为像这样工作的嵌套映射:{firstkey={secondkey={thirdkey="Example value"}}},我的 deepkeymap 实际上存储了 4 个具有 4 个值的键(数量键和值会改变)。我已经完成了这一点,但并不完全,因为它只转换了我的 deepkeymap 的最后一个键和值,事实上,我放的示例是我的嵌套映射的输出,这里是代码:

public void save() {
    try {
        Map<String, Object> datamap = new HashMap<String, Object>();
        for(String key : deepkeymap.keySet()) {
            Object value = deepkeymap.get(key);
            int end = key.length();
            for(int start; (start = key.lastIndexOf('.', end - 1)) != -1; end = start) {
                value = new HashMap<>(Collections.singletonMap(key.substring(start + 1, end), value));
            }
            datamap.putAll(new HashMap<>(Collections.singletonMap(key.substring(0, end), value)));
        }
        System.out.println("Datamap: "+datamap);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

如上所述,输出为:

Datamap: {firstkey={secondkey={thirdkey="Example value"}}}

但它应该有另外 3 个键,因为 deepkeymap 包含 4 个键和它们各自的 4 个值,我已经检查过它们存储在上面并且没有人有空值,对 keySet 循环打印键和值进行调试。

【问题讨论】:

  • 这充满了问题。值和键可以是字符串或映射。听起来你可以有不同级别的键。 Imo,这使用起来很麻烦(它可能需要instanceof 检查和casting)。我建议你讨论你的整体任务,保证这一点。有人可能会帮助您提出更合适的解决方案。或者只是不理会它并按原样使用。
  • @WJS 实际上,我的 deepkeymap 的每个键都是带有 Object 值的字符串,我确信这一点,因为我正在使用一个类来转换存储在资源文件夹中的 yml 文件的每个键以点分隔的字符串形式对此映射进行检查,因此我的 deepkeymap 是 100% 映射,并且转换工作如输出所示,但是,它只输出存储在 deepkeymap 上的最后一个键.
  • 存在 YAML 解析器,它们会返回您所说的数据结构。您可以考虑使用其中之一,而不是重新发明轮子。
  • @RoddyoftheFrozenPeas 我为此使用了 SnakeYAML,但这里的重点是我设置了这个方法(字符串路径,对象值),其中路径是一个“dot.separated.string”,表示嵌套映射,get(String path) 也一样,所以我在这里的解决方案是创建一个 Map 用点分隔的字符串及其值,然后,当我想保存文件时,转换点分隔字符串到嵌套映射中并将它们转储到文件中,这是另一篇关于它的帖子stackoverflow.com/questions/67938579/…。

标签: java


【解决方案1】:

您可以使用下面的代码。工厂方法因输入错误而失败,而且DeepKeyMap只有toString。下面是一个 JUnit 测试,它只运行代码并且什么都不测试。如果您将来使用它,您可以将 DeepKeyMap 提取到一个单独的类中。

public class MapTest
{
    static class DeepKeyMap
    {
        Map<String, Object> map = new HashMap<>();

        public void put(
                String path,
                Object value
        )
        {
            String[] split = path.split("\\.");

            this.put(split, value);
        }

        public void put(
                String[] path,
                Object value
        )
        {
            Map<String, Object> deepestMap = createMapsToTheDeepestKey(path);
            String deepestKey = path[path.length - 1];

            deepestMap.put(deepestKey, value);
        }

        private Map<String, Object> createMapsToTheDeepestKey(String[] path)
        {
            Map<String, Object> deepestMap = map;

            for (int i = 0; i < path.length - 1; i++)
            {
                String key = path[i];
                deepestMap = getDeeperMap(deepestMap, key);
            }

            return deepestMap;
        }

        private Map<String, Object> getDeeperMap(
                Map<String, Object> deepestMap,
                String key
        )
        {
            if (!deepestMap.containsKey(key))
            {
                deepestMap.put(key, new HashMap<>());
            }

            return (Map<String, Object>) deepestMap.get(key);
        }

        @Override
        public String toString()
        {
            return map.toString();
        }

        public static DeepKeyMap from(Map<String, Object> original)
        {
            DeepKeyMap result = new DeepKeyMap();

            // the for loop can be minimized to
            // original.forEach(result::put);
            for (var entry : original.entrySet())
            {
                result.put(entry.getKey(), entry.getValue());
            }

            return result;
        }
    }

    @Test
    void test()
    {
        Map<String, Object> original = Map.of("flat", "First Level",
                "nested.value.one", "Second Level",
                "nested.value.two", "Third Level",
                "nested.different.value.one", "Fourth Level"
        );

        DeepKeyMap deepMap = DeepKeyMap.from(original);

        System.out.println(deepMap);
    }
}

编辑:我稍微重构了上面的代码。希望它更清楚它的作用。

【讨论】:

    【解决方案2】:

    我不会那样使用它,你可以在不同的级别上有相同的键,这不是 Map 的意图。

    此外,您可以生成一个结构,其键类型为映射或字符串。这带来了各种不确定性。

    您应该考虑使用其他数据结构或数据库。

    您的意图是什么,也许我们可以为您提供帮助。

    【讨论】:

    • 这不是答案,而是评论,基本上重复了我已经说过的话。当您获得 50+ 代表时,您将能够发表评论。
    猜你喜欢
    • 2014-04-09
    • 1970-01-01
    • 2020-11-12
    • 2016-11-14
    • 2019-12-23
    • 1970-01-01
    • 2015-10-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多