gpt4 book ai didi

java - 展平和取消展平 HashMap 的最佳方法

转载 作者:行者123 更新时间:2023-12-01 13:56:12 24 4
gpt4 key购买 nike

我想弄平一个 HashMap像这个例子中的例子。请注意,数据不是 JSON 格式,这只是一个伪代码:

nested = {
"one": {
"two": {
"2a": "x",
"2b": "y"
}
},
"side": "value"
}

// output: { "one.two.2a": "x", "one.two.2b": "y", "side": "value" }

不幸的是,我找不到任何引用实现,所以我想出了我的递归解决方案,如下所示。有没有更好的方法(在不使用递归或性能或安全性或清洁度方面:))来实现这一目标?输出应该是另一个 HashMap以扁平形式。

我会将结果用于这种目的 https://redislabs.com/redis-best-practices/data-storage-patterns/object-hash-storage/
public class Flat {

public static void flatten(Map<String, ?> target, Map<String, String> result, String path) {
for (var entry : target.entrySet()) {
var next = path.equals("") ? entry.getKey() : path + "." + entry.getKey();
if (entry.getValue() instanceof Map) {
flatten((Map) entry.getValue(), result, next);
} else {
result.put(next, entry.getValue().toString());
}
}
}

public static Map unflatten(Map<String, String> target) {
var result = new HashMap<String, Object>();
for (var entry : target.entrySet()) {
if (entry.getKey().split(".").length == 1) {
result.put(entry.getKey(), entry.getValue());
} else {
var path = entry.getKey().split(".");
Map<String, Object> current = new HashMap<>();
for (var i = 0; i < path.length - 1; i++) {
if (result.containsKey(path[i])) {
current = (Map) (result.get(path[i]));
} else {
current = new HashMap<>();
result.put(path[i], current);
}
}
current.put(path[path.length - 1], entry.getValue());
}
}
return result;
}
}

最佳答案

如果你想清理递归代码,那么你可以像下面这样更新它:

public static Map<String, String> flatten(Map<String, ?> source) {
Map<String, String> converted = new HashMap<>();

for (var entry : source.entrySet()) {
if (entry.getValue() instanceof Map) {
flatten((Map<String, Object>) entry.getValue())
.forEach((key, value) -> converted.put(entry.getKey() + "." + key, value));
} else {
converted.put(entry.getKey(), entry.getValue().toString());
}
}

return converted;
}

感谢评论,我也研究了堆栈解决方案。您可以重写 flatten 以使用以下示例。您应该使用哪一个取决于开发人员的技能水平,因为堆叠版本更难理解。
private static class StackElement {
Optional<String> key;
Map<String, ?> elements;

public StackElement(String key, Map<String, ?> elements) {
this.key = Optional.ofNullable(key);
this.elements = elements;
}
}

public static Map<String, String> flattenNonRecursive(Map<String, ?> source) {
Map<String, String> converted = new HashMap<>();

Stack<StackElement> stack = new Stack();
stack.push(new StackElement(null, source));

while (!stack.empty()) {
var frame = stack.pop();

for (var entry : frame.elements.entrySet()) {
var frameKey = frame.key
.map(k -> k + ".")
.orElse("") + entry.getKey();

if (entry.getValue() instanceof Map) {
stack.push(new StackElement(frameKey, (Map<String, ?>) entry.getValue()));
} else {
converted.put(frameKey, entry.getValue().toString());
}
}
}

return converted;
}

关于性能,非递归更快。我使用带有 Map.of("sample.test.two", "one", "test.sample.two", "three", "four", "file") 的 map 进行了一个小实验。 .

调用该方法 1000 次,性能差异为:
Recursive took:         20957300
Non recursive took: 13376000

至于您的 unflatten,这包含错误。在一次测试运行中,我使用了一个只包含两个元素的简单 map ,它因索引超出范围而崩溃。这与您使用 result 有关和 current在不正确的地方。下面是一个略有改动的工作副本:
public static Map<String, ?> unflatten(Map<String, String> target) {
var result = new HashMap<String, Object>();

for (var entry : target.entrySet()) {
var split = entry.getKey().split("\\.");
if (split.length == 1) {
result.put(entry.getKey(), entry.getValue());
continue;
}

var current = result;
for (int i = 0; i < split.length - 1; i++) {
current = (HashMap<String, Object>) current.computeIfAbsent(
split[i], p -> new HashMap<String, Object>());
}
current.put(split[split.length - 1], entry.getValue());
}

return result;
}

关于java - 展平和取消展平 HashMap 的最佳方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61865457/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com