如何在 Java 中扁平化字典数组



我正在研究以下问题,我需要扁平化字典数组:

例如 - 下面是一个输入:

[
    {'a':
        {'b':
            {'c':
                {'d':'e'}
            }
        }
    }, 
    {'a':{'b':{'c':{'d':{'e':'f'}}}}},
    {'a':'b'}
]

输出将是:

[
    {'a_b_c_d':'e'}, 
    {'a_b_c_d_e':'f'},
    {'a':'b'}
]

以下是我能够想到的。有没有更好的方法来解决这个问题?

private static List<Map<String, String>> flatDictionary(final List<Map<String, Object>> input) {
    List<Map<String, String>> listHolder = new ArrayList<>();
    if(input == null || input.isEmpty()) {
        return listHolder;
    }
    for(Map<String, Object> mapHolder : input) {
        Map<String, String> m = new HashMap<>();
        StringBuilder sb = new StringBuilder();
        Map<String, String> output = helper(mapHolder, sb, m);
        listHolder.add(output);
    }
    return listHolder;
}
private static Map<String, String> helper(final Map<String, Object> map, final StringBuilder sb, final Map<String, String> output) {
    String mapValue = null;
    for(Map.Entry<String, Object> holder : map.entrySet()) {
        String key = holder.getKey();
        Object value = holder.getValue();
        if(value instanceof Map) {
            sb.append(key).append("_");
            helper((HashMap<String, Object>) value, sb, output);
        } else if(value instanceof String) {
            sb.append(key);
            mapValue = (String) value;
        }
        output.put(sb.toString(), mapValue);
    }
    return output;
}

我会使用递归。

首先定义一个平展单个Map的方法

public static void flatten(final String keyPrefix, final Map<String, Object> input, final Map<String, Object> output) {
    for (final Map.Entry<String, Object> e : input.entrySet()) {
        final var key = keyPrefix.isBlank() ? e.getKey() : keyPrefix + "_" + e.getKey();
        if (e.getValue() instanceof Map) {
            // if the nested Map is of the wrong type bad things may happen
            flatten(key, (Map<String, Object>) e.getValue(), output);
        } else {
            output.put(key, e.getValue());
        }
    }
}

注意:这不会尝试处理重复的键。

用法:

public static void main(final String[] args) throws InterruptedException {
    final var data = Map.of(
            "A", Map.of("a", "Expect A_a"),
            "B", Map.of("b1", Map.of(
                    "bb1", "expect B_b1_bb1",
                    "bb2", "expect B_b1_bb2"
            )),
            "C", "Expect C");
    final var output = new HashMap<String, Object>();
    flatten("", data, output);
    output.forEach((k, v) -> System.out.printf("%s -> %s%n", k, v));
}

输出:

C -> Expect C
A_a -> Expect A_a
B_b1_bb2 -> expect B_b1_bb2
B_b1_bb1 -> expect B_b1_bb1

现在,只需定义一个循环获取List的方法

public static final Map<String, Object> flattenAll(final List<Map<String, Object>> input) {
    final var output = new HashMap<String, Object>();
    input.forEach(map -> flatten("", map, output));
    return output;
}

注意:这不会尝试处理重复的键。

最新更新