Повторять, находить и обновлять значение во вложенной карте<String,?>
У меня есть файл YML, который я анализирую в Map, используя библиотеку yamlBeans. Я не знаю, насколько глубока вложенная карта. например:
- key1:
- ключ2: значение1
- ключ3:
- ключ4: значение2
- ключ5: значение3
Мне нужно найти конкретное значение на этой карте, обновить его и записать карту обратно в файл YML (что я знаю, как это сделать).
Это мой код для обновления значения, и он работает.Тем не менее, это повторяется только дважды по вложенной карте, и мне нужно, чтобы это повторялось столько, сколько нужно:
static void updateYmlContent(Map<String, ?> ymlMap, String value, String... keys) {
boolean found = false;
for (Map.Entry entry : ymlMap.entrySet()) {
if (entry.getKey().equals(keys[0])) {
found = true;
for (Map.Entry subEntry : ((Map<?, ?>) entry.getValue()).entrySet()) {
if (subEntry.getKey().equals(keys[1])) {
subEntry.setValue(value);
break;
} else {
throwKeyNotFoundException(keys[1]);
}
}
break;
}
}
if (!found) {
throwKeyNotFoundException(keys[0]);
}
}
3 ответа
Используйте рекурсию и счетчик глубины, чтобы пролистать каждый уровень карты. Я не компилировал это, так что, вероятно, нужно немного доработать, но вот основная идея:
static void updateYmlContent(Map<String, ?> ymlMap, String value, String... keys) {
int depth = 0;
findAndReplaceContent(ymlMap, value, keys, depth);
}
static void findAndReplaceContent(Map map, .......) {
if (map.containsKey(keys[depth]))
{
if (depth == keys.length - 1)
{
// found it
map.put(keys[depth], value);
// done
}
else
{
findAndReplaceContent(map.get(keys[depth]), value, keys, depth+1);
}
}
else
{
// throw key not found
}
}
Если ymlMap
изменчиво, оно должно быть типа Map<String, Object>
(в идеале), я полагаю, вы уже проверили это.
@SuppressWarnings("unchecked")
static void updateYmlContent(Map<String, ?> ymlMap, String value, String... keys)
{
for (int i = 0, lastIndex = keys.length - 1; i <= lastIndex; i++)
{
String key = keys[i];
Object v = ymlMap.get(key);
if (v == null) // Assumed value is never null, if key exists
throw new /* KeyNotFound */ RuntimeException("Key '" + key + "' not found");
if (i < lastIndex)
ymlMap = (Map<String, Object>) v;
else
((Map<String, String>) ymlMap).put(key, value);
}
}
Вы можете сделать это через один for
цикл, пожалуйста, смотрите пример:
private static void updateYmlContent(Map<String, Object> map, String newValue, String... keys) {
for (int i = 0; i < keys.length; i++) {
if (i + 1 == keys.length) {
map.put(keys[i], newValue);
return;
}
if (map.get(keys[i]) instanceof Map) {
map = (Map<String, Object>) map.get(keys[i]);
} else {
throw new RuntimeException();
}
}
throw new RuntimeException();
}
Также, пожалуйста, посмотрите, как это используется:
public static void main(String[] keys) throws Exception {
Map<String, Object> ymlMap = new HashMap<>();
Map<Object, Object> nested1 = new HashMap<>();
Map<Object, Object> nested2 = new HashMap<>();
nested2.put("key3", "oldvalue1");
nested2.put("key4", "oldvalue2");
nested1.put("key2", nested2);
ymlMap.put("key1", nested1);
updateYmlContent(ymlMap, "new", "key1", "key2", "key3");
}