取消标记值为

时间:2018-01-19 09:04:28

标签: java

我目前有一个格式为

的键值对映射
a.b.c: value1
e.f: value2
g: [
  g.h: nested_value1
  g.i: nested_value2
]

我需要在平面结构中“取消”这个新地图 -

a:
  b:
    c: value1
e:
  f: value2
g: [
  h: nested_value1
  i: nested_value2
]

我当前的尝试没有走得太远,并抛出ConcurrentModificationException

private static Map<String, Object> unflatten(Map<String, Object> flattened) {
    Map<String, Object> unflattened = new HashMap<>();
    for (String key : flattened.keySet()) {
        doUnflatten(flattened, unflattened, key, flattened.get(key));
    }
    return unflattened;
}

private static Map<String, Object> doUnflatten(
    Map<String, Object> flattened,
    Map<String, Object> unflattened,
    String key,
    Object value) {

    String[] parts = StringUtils.split(key, '.');
    for (int i = 0; i < parts.length; i++) {
        String part = parts[i];
        Object current = flattened.get(part);
        if (i == (parts.length - 1)) {
            unflattened.put(part, value);
        } else if (current == null) {
            if ((current = unflattened.get(part)) == null) {
                current = new HashMap<>();
            }
            unflattened.put(part, current);
            unflattened = (Map<String, Object>) current;
        } else if (current instanceof Map) {
            unflattened.put(part, current);
            unflattened = (Map<String, Object>) current;
        }
    }
    return unflattened;
}

我错过了一些明显的东西吗?一种解决方案是使用像JsonFlattener这样的库 - 唯一的问题是这将涉及在JSON之间进行前后转换。

编辑:感谢指点 - 我在那里,有一件事我忘了提到它还需要解决HashMaps的集合

4 个答案:

答案 0 :(得分:1)

您的错误来自于您迭代密钥集然后更改地图,而不是通过迭代器。

  

所有这类&#34;集合视图返回的迭代器   方法&#34;快速失败:如果地图在任何地方进行了结构修改   创建迭代器之后的时间,除了通过之外的任何方式   迭代器自己的remove方法,迭代器会抛出一个   ConcurrentModificationException的。因此,面对并发   修改,迭代器快速而干净地失败,而不是   在不确定的时间冒着任意的,非确定性的行为   在将来。

您可以使用新地图来解决这个问题。

答案 1 :(得分:1)

您的实现问题在于您将输出写入用于输入的同一Map,这会导致ConcurrentModificationException

对于输出单独的Map,实现变得简单:

Map<String,Object> unflattened = new HashMap<>();
for (Map.Entry<String,Object> e : flattened.entrySet()) {
    String[] parts = StringUtils.split(e.getKey(), ".");
    // Find the map to be used as a destination for put(...)
    Map<String,Object> dest = unflattened;
    for (int i = 0 ; i != parts.length-1 ; i++) {
        Object tmp = dest.get(parts[i]);
        if (tmp == null) {
            // We did not see this branch yet
            Map<String,Object> next = new HashMap<>();
            dest.put(parts[i], next);
            dest = next;
            continue;
        }
        if (!(temp instanceof Map)) {
            throw new IllegalStateException();
        }
        dest = (Map<String,Object>)temp;
    }
    // Put the entry into the destination Map<>
    dest.put(parts[parts.length-1], e.getValue());
}

请注意,当初始地图描述不一致的层次结构时,“unflattening”的过程可能会失败,例如,具有分支和具有相同名称的叶子的层次结构:

"a.b.c" -> "x" // OK: "a.b" is a branch
"a.b.d" -> "y" // OK: "a.b" is a branch
"a.b"   -> "z" // Error: "a.b" is a leaf

答案 2 :(得分:1)

为您的结果创建一个新的Map实例,而不是尝试重用当前的实例。另外,发送地图值,因此不需要提取:

private static Map<String, Object> unflatten(Map<String, Object> flattened) {
    Map<String, Object> unflattened = new HashMap<>();
    for (String key : flattened.keySet()) {
        doUnflatten(unflattened, key, flattened.get(key));
    }
    return unflattened;
}

这也可以防止原始键出现在生成的地图中。

以上还需要略微重写doUnflatten方法:

private static void doUnflatten(Map<String, Object> current, String key,
  Object originalValue) {
    String[] parts = StringUtils.split(key, ".");
    for (int i = 0; i < parts.length; i++) {
        String part = parts[i];
        if (i == (parts.length - 1)) {
            current.put(part, originalValue);
            return;
        }

        Map<String, Object> nestedMap = (Map<String, Object>) current.get(part);
        if (nestedMap == null) {
            nestedMap = new HashMap<>();
            current.put(part, nestedMap);
        }

        current = nestedMap;
    }
}

注意事项:没有必要从方法中返回地图。将循环划分为两种不同的情况:应将值写入映射,或者应创建或检索嵌套映射。

答案 3 :(得分:0)

最简单的解决方案是替换行

for (String key : flattened.keySet()) {

for (String key : new ArrayList<>(flattened.keySet())) {

但是对于大数据量,从性能角度来看,它可能不是很有效。