Java - 递归获取地图的所有键
Java - Get all keys of a map recursively
所以目前我正在使用 SnakeYaml 开发一个 yml 文件更新程序,但是我有这个问题我不知道如何解决。
这是我的 class 获取 yaml 文件的所有键作为 Set:
public class YamlKeys {
private static Set<String> keys = new HashSet<String>();
private static String path = "";
YamlKeys(Map<?, ?> data) {
getKeysRecursive(data);
}
private void getKeysRecursive(final Map<?, ?> data) {
for(Object key : data.keySet()) {
final Object value = data.get(key);
if(key instanceof String) {
if(path.length() == 0) {
path = (String)key;
} else {
path = path+"."+(String)key;
}
}
if(value instanceof Map) {
getKeysRecursive((Map<?, ?>) value);
} else {
keys.add(path);
if(path.contains(".")) {
path = path.substring(0, path.lastIndexOf("."));
}
}
}
path = "";
}
Set<String> getKeys() {
return keys;
}
}
这是我的 yml 文件:
FirstKey:
SecondKey:
Enabled: true
ID: "Some text"
AnotherKey:
AValue: true
TestKey:
TestValue: "More text"
我是这样称呼它的:
new YamlKeys(data).getKeys().stream().forEach(key -> System.out.println(key));
输出为:
FirstKey.SecondKey.AnotherKey.AValue
FirstKey.SecondKey.Enabled
FirstKey.SecondKey.ID
TestKey.TestValue
问题出在最后一个,因为它应该是“FirstKey.SecondKey.TestKey.TestValue”,但是前两个键由于路径重置而被删除,如果更多键被添加到“,则需要此路径重置” FirstKey”,但我不知道如何解决。
弹出 path
最后一部分的代码也应该在处理地图后应用:
if(value instanceof Map) {
getKeysRecursive((Map<?, ?>) value);
} else {
keys.add(path);
}
if(path.contains(".")) {
path = path.substring(0, path.lastIndexOf("."));
}
此外,当您在 getKeysRecursive
末尾重置路径时,您将丢弃有关您在树中有多深的上下文。因此,当您的最深地图完成处理时,它会清除 path
,但父地图尚未完成处理。
试图从递归调用中管理这个单个可变 path
变量的状态是很棘手的。这可以通过像这样传递路径来更好地完成:
private void getKeysRecursive(final Map<?, ?> data, String parentPath)
您也可以考虑使用集合,可能会清理一些围绕初始状态的 if-else 逻辑。
private void getKeysRecursive(final Map<?, ?> data, List<Object> parentPath) {
for(Object key : data.keySet()) {
List<Object> path = new ArrayList<>(parentPath);
path.add(key);
final Object value = data.get(key);
if(value instanceof Map) {
getKeysRecursive((Map<?, ?>) value, path);
} else {
keys.add(path.stream().map(Objects::toString).collect(Collectors.joining(".")));
}
}
}
并以 app.getKeysRecursive(data, Collections.emptyList());
开始
所以目前我正在使用 SnakeYaml 开发一个 yml 文件更新程序,但是我有这个问题我不知道如何解决。
这是我的 class 获取 yaml 文件的所有键作为 Set
public class YamlKeys {
private static Set<String> keys = new HashSet<String>();
private static String path = "";
YamlKeys(Map<?, ?> data) {
getKeysRecursive(data);
}
private void getKeysRecursive(final Map<?, ?> data) {
for(Object key : data.keySet()) {
final Object value = data.get(key);
if(key instanceof String) {
if(path.length() == 0) {
path = (String)key;
} else {
path = path+"."+(String)key;
}
}
if(value instanceof Map) {
getKeysRecursive((Map<?, ?>) value);
} else {
keys.add(path);
if(path.contains(".")) {
path = path.substring(0, path.lastIndexOf("."));
}
}
}
path = "";
}
Set<String> getKeys() {
return keys;
}
}
这是我的 yml 文件:
FirstKey:
SecondKey:
Enabled: true
ID: "Some text"
AnotherKey:
AValue: true
TestKey:
TestValue: "More text"
我是这样称呼它的:
new YamlKeys(data).getKeys().stream().forEach(key -> System.out.println(key));
输出为:
FirstKey.SecondKey.AnotherKey.AValue
FirstKey.SecondKey.Enabled
FirstKey.SecondKey.ID
TestKey.TestValue
问题出在最后一个,因为它应该是“FirstKey.SecondKey.TestKey.TestValue”,但是前两个键由于路径重置而被删除,如果更多键被添加到“,则需要此路径重置” FirstKey”,但我不知道如何解决。
弹出 path
最后一部分的代码也应该在处理地图后应用:
if(value instanceof Map) {
getKeysRecursive((Map<?, ?>) value);
} else {
keys.add(path);
}
if(path.contains(".")) {
path = path.substring(0, path.lastIndexOf("."));
}
此外,当您在 getKeysRecursive
末尾重置路径时,您将丢弃有关您在树中有多深的上下文。因此,当您的最深地图完成处理时,它会清除 path
,但父地图尚未完成处理。
试图从递归调用中管理这个单个可变 path
变量的状态是很棘手的。这可以通过像这样传递路径来更好地完成:
private void getKeysRecursive(final Map<?, ?> data, String parentPath)
您也可以考虑使用集合,可能会清理一些围绕初始状态的 if-else 逻辑。
private void getKeysRecursive(final Map<?, ?> data, List<Object> parentPath) {
for(Object key : data.keySet()) {
List<Object> path = new ArrayList<>(parentPath);
path.add(key);
final Object value = data.get(key);
if(value instanceof Map) {
getKeysRecursive((Map<?, ?>) value, path);
} else {
keys.add(path.stream().map(Objects::toString).collect(Collectors.joining(".")));
}
}
}
并以 app.getKeysRecursive(data, Collections.emptyList());