如何展平 HashMap?
How to Flatten a HashMap?
我有一个嵌套的 HashMap
这种形式:
{key1=val1, key2=val2,
key3=[
{key4=val4, key5=val5},
{key6=val6, key7=val7}
]
}
我现在想展平那张地图,以便所有条目都在同一层上:
{key1=val1, key2=val2, key4=val4, key5=val5,key6=val6, key7=val7}
当我尝试时
map.values().forEach(map.get("key3")::addAll);
as described in this post,我得到以下错误:
invalid method reference
cannot find symbol
symbol: method addAll(T)
location: class Object
where T is a type-variable:
T extends Object declared in interface Iterable
是否有任何通用的方法来展平任何给定的 Map
?
你应该试试这个:
Map<String, Object> flatenedMap = new HashMap<>();
map.forEach((key, value) -> {
if(value instanceof Map) {
flatenedMap.putAll((Map) value);
} else {
flatenedMap.put(key, value);
}
});
如果你有不止一层的嵌套,你可以使用递归算法。
static Map<String, Object> flatMap(Map<String, Object> map) {
Map<String, Object> flatenedMap = new HashMap<>();
map.forEach((key, value) -> {
if(value instanceof Map) {
flatenedMap.putAll(flatMap((Map) value));
} else {
flatenedMap.put(key, value);
}
});
return flatenedMap;
}
不确定我是否正确理解了这个问题,但这样的事情可能会奏效。
还没有检查所有语法,所以可能某处有错误。
Stream<Map.Entry<String, String>> flatten(Map<String, Object> map) {
return map.entrySet()
.stream()
.flatMap(this::extractValue);
}
Stream<Map.Entry<String, String>> extractValue(Map.Entry<String, Object> entry) {
if (entry.getValue() instanceof String) {
return Stream.of(new AbstractMap.SimpleEntry(entry.getKey(), (String) entry.getValue()));
} else if (entry.getValue() instanceof Map) {
return flatten((Map<String, Object>) entry.getValue());
}
}
那么你可以这样做:
Map<String, String> flattenedMap = flatten(yourmap)
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
您可以使用递归辅助方法:
static void forEachValue(Map<String, Object> source, BiConsumer<? super String, ? super Object> action) {
for (final Map.Entry<String, Object> entry : source.entrySet()) {
if (entry.getValue() instanceof Map) {
forEachValue((Map<String, Object>) entry.getValue(), action);
} else {
action.accept(entry.getKey(), entry.getValue());
}
}
}
然后可以这样调用:
Map<String, Object> map = ...;
Map<String, Object> flattened = new HashMap<>();
forEachValue(map, map::put);
我已经将这种方法与 BiConsumer
一起使用,以不限制该方法仅将嵌套映射展平到另一个映射中,但调用者可以自己决定他想对每个键值对做什么.
我有一个嵌套的 HashMap
这种形式:
{key1=val1, key2=val2,
key3=[
{key4=val4, key5=val5},
{key6=val6, key7=val7}
]
}
我现在想展平那张地图,以便所有条目都在同一层上:
{key1=val1, key2=val2, key4=val4, key5=val5,key6=val6, key7=val7}
当我尝试时
map.values().forEach(map.get("key3")::addAll);
as described in this post,我得到以下错误:
invalid method reference
cannot find symbol
symbol: method addAll(T)
location: class Object
where T is a type-variable:
T extends Object declared in interface Iterable
是否有任何通用的方法来展平任何给定的 Map
?
你应该试试这个:
Map<String, Object> flatenedMap = new HashMap<>();
map.forEach((key, value) -> {
if(value instanceof Map) {
flatenedMap.putAll((Map) value);
} else {
flatenedMap.put(key, value);
}
});
如果你有不止一层的嵌套,你可以使用递归算法。
static Map<String, Object> flatMap(Map<String, Object> map) {
Map<String, Object> flatenedMap = new HashMap<>();
map.forEach((key, value) -> {
if(value instanceof Map) {
flatenedMap.putAll(flatMap((Map) value));
} else {
flatenedMap.put(key, value);
}
});
return flatenedMap;
}
不确定我是否正确理解了这个问题,但这样的事情可能会奏效。 还没有检查所有语法,所以可能某处有错误。
Stream<Map.Entry<String, String>> flatten(Map<String, Object> map) {
return map.entrySet()
.stream()
.flatMap(this::extractValue);
}
Stream<Map.Entry<String, String>> extractValue(Map.Entry<String, Object> entry) {
if (entry.getValue() instanceof String) {
return Stream.of(new AbstractMap.SimpleEntry(entry.getKey(), (String) entry.getValue()));
} else if (entry.getValue() instanceof Map) {
return flatten((Map<String, Object>) entry.getValue());
}
}
那么你可以这样做:
Map<String, String> flattenedMap = flatten(yourmap)
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
您可以使用递归辅助方法:
static void forEachValue(Map<String, Object> source, BiConsumer<? super String, ? super Object> action) {
for (final Map.Entry<String, Object> entry : source.entrySet()) {
if (entry.getValue() instanceof Map) {
forEachValue((Map<String, Object>) entry.getValue(), action);
} else {
action.accept(entry.getKey(), entry.getValue());
}
}
}
然后可以这样调用:
Map<String, Object> map = ...;
Map<String, Object> flattened = new HashMap<>();
forEachValue(map, map::put);
我已经将这种方法与 BiConsumer
一起使用,以不限制该方法仅将嵌套映射展平到另一个映射中,但调用者可以自己决定他想对每个键值对做什么.