I have a map read from my static config in the following format: Map<String, Map<String, List<String>>> dependentPluginEntityMapString
. The string values in this map are actually from ENUMs and the correct and required representation of the map is Map<ENUM_A, Map<ENUM_A, List<ENUM_B>>>
.
ENUM_A {
APPLE, BANANA
}
ENUM_B {
ONION, RADDISH
}
Map<ENUM_A, Map<ENUM_A, List<ENUM_B>>>
for more type safety?I know, I can iterate on the string map (using for or streams) and create a new map with enums as required but looking for a better/more efficient and an elegant way of doing that?
This is my brute solution. Can i do better?
final Map<ENUM_A, Map<ENUM_A, List<ENUM_B>>> dependentPluginEntityMap = new HashMap<>();
for (Map.Entry<String, Map<String, List<String>>> dependentPluginEntry:
dependentPluginEntityMapFromAppConfig.entrySet()) {
final Map<ENUM_A, List<ENUM_B>> independentPluginMapForEntry = new HashMap<>();
if (MapUtils.isNotEmpty(dependentPluginEntry.getValue())) {
for (Map.Entry<String, List<String>> independentPluginEntry:
dependentPluginEntry.getValue().entrySet()) {
if (CollectionUtils.isNotEmpty(independentPluginEntry.getValue())) {
independentPluginMapForEntry.put(ENUM_A.valueOf(independentPluginEntry.getKey()),
independentPluginEntry.getValue().stream().map(value -> ENUM_B.valueOf(value))
.collect(Collectors.toList()));
}
}
}
dependentPluginEntityMap.put(ENUM_A.valueOf(dependentPluginEntry.getKey()),
independentPluginMapForEntry);
}
Any leads apprecciated.
This does not look pretty but uses streams and converts to Map<ENUM_A, Map<ENUM_A, List<ENUM_B>>>
using EnumMap for the each Map.
Map<String, Map<String, List<String>>> in = Map.of(
"APPLE", Map.of("APPLE", List.of("RADDISH"), "BANANA", List.of("ONION", "RADDISH"))
,"BANANA", Map.of("APPLE", List.of("ONION", "RADDISH"), "BANANA", List.of("ONION"))
);
Map<ENUM_A, Map<ENUM_A, List<ENUM_B>>> out2 = in.entrySet().stream()
.map(e -> Map.entry(ENUM_A.valueOf(e.getKey()),
e.getValue().entrySet().stream()
.map(x -> Map.entry(ENUM_A.valueOf(x.getKey()),
x.getValue().stream().map(ENUM_B::valueOf).collect(Collectors.toList())))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -> b, () -> new EnumMap<>(ENUM_A.class)))))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -> b, () -> new EnumMap<>(ENUM_A.class)));
System.out.println("out2="+out2);
=>
out2={APPLE={APPLE=[RADDISH], BANANA=[ONION, RADDISH]}, BANANA={APPLE=[ONION, RADDISH], BANANA=[ONION]}}
It looks a bit neater if you revert to the default toMap()
handling by deleting the , (a, b) -> b, () -> new EnumMap<>(ENUM_A.class)
from within each toMap
call.
EDIT
However I find it easier to define 2 simple utility methods which can be added to any helper class to transform Map<K,V> to Map<X,Y>
and List<X> to List<Y>
:
/**
* Utility to convert List<X> to List<Y> by applying mapper function
*/
static <X,Y> List<Y> toList(List<X> list, Function<X,Y> valueMapper) {
return list.stream().map(valueMapper).collect(Collectors.toList());
}
/**
* Utility to convert Map<K,V> to Map<X,Y> by applying mapper functions
*/
static <K,V,X,Y> Map<X, Y> toMap(Map<K, V> map, Function<K,X> keyMapper, Function<V,Y> valueMapper) {
return map.entrySet().stream()
.collect(Collectors.toMap(k -> keyMapper.apply(k.getKey()), v -> valueMapper.apply(v.getValue())));
}
With these definitions your transformation is reduced to applications of the above:
Map<ENUM_A, Map<ENUM_A, List<ENUM_B>>> map
= toMap(in, ENUM_A::valueOf,
mValue -> toMap(mValue, ENUM_A::valueOf, lValue -> toList(lValue, ENUM_B::valueOf)));
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.