Я не смог найти встроенный ответ, но это полный автономный метод, который можно использовать в качестве мета-метода на карте для выполнения того, что вы хотите:
Map map = ['a.b.c': 'Hi', 'a.b.d': 'Yo', 'f.g.h': 'Howdy']
Map.metaClass.expandKeys = { separator = '.' ->
def mergeMaps = { a, b ->
b.each{ k, v ->
if(a[k] && (v instanceof Map)) {
mergeMaps(a[k], v)
} else {
a[k] = v
}
}
a
}
delegate.inject([:]){ result, k, v ->
mergeMaps(result, k.tokenize(separator).reverse().inject(v){last, subkey -> [(subkey):last] })
}
}
assert map.expandKeys() == [a:[b:[c:"Hi", d:"Yo"]], f:[g:[h:"Howdy"]]]
Он также позволяет использовать разделители, отличные от .
, просто передайте разделитель в метод expandKeys
Если вы хотите использовать его как обычную функцию, вы можете сделать это вместо этого:
Map map = ['a.b.c': 'Hi', 'a.b.d': 'Yo', 'f.g.h': 'Howdy']
def expandKeys = { Map input, separator = '.' ->
def mergeMaps = { a, b ->
b.each{ k, v ->
if(a[k] && (v instanceof Map)) {
mergeMaps(a[k], v)
} else {
a[k] = v
}
}
a
}
input.inject([:]){ result, k, v ->
mergeMaps(result, k.tokenize(separator).reverse().inject(v){last, subkey -> [(subkey):last] })
}
}
assert expandKeys(map) == [a:[b:[c:"Hi", d:"Yo"]], f:[g:[h:"Howdy"]]]
Основной трюк, помимо объединения карт, состоит в том, чтобы разделить, а затем повернуть каждый ключ.Тогда окончательная иерархия может быть построена в обратном направлении.Кроме того, может быть лучший способ справиться со слиянием, потому что мне не нравится зависание a
в конце.