I am trying to make a new Map from a another Map where some of the values are keys in other entries.
Example:
HashMap<String,String> testMap = new HashMap<>();
testMap.put("a","b");
testMap.put("b","d");
testMap.put("d","e");
testMap.put("e","f");
testMap.put("k","r");
I need as result a new Map with this format:
a->f
b->f
d->f
e->f
k->r
producedMap.put("a","f");
producedMap.put("b","f");
producedMap.put("d","f");
producedMap.put("e","f");
producedMap.put("k","r");
My code is that, but seems not give the true result.
public HashMap<String,String> getMatched(HashMap<String,String> correpondanceMap){
Collection<String> correpondanceKeys = correpondanceMap.keySet();
HashMap<String,String> newCorrepondanceMap= new HashMap<>();
correpondanceMap.entrySet().forEach(entry->{
if (correpondanceKeys.contains(entry.getValue())){
String newValue = entry.getValue();
String keyOfnewValue = correpondanceMap
.entrySet()
.stream()
.filter(entriii -> newValue.equals(entry.getValue()))
.map(Map.Entry::getKey).limit(1).collect(Collectors.joining());
newCorrepondanceMap.put(keyOfnewValue,correpondanceMap.get(newValue));
}
else
{
newCorrepondanceMap.put(entry.getKey(),entry.getValue());
}
});
newCorrepondanceMap.entrySet().forEach(entry-> System.out.println(entry.getKey() +" -- > " +entry.getValue()));
return newCorrepondanceMap;
}
You can achieve that by some simple recursion logic in a helper function:
public static String findCorrespondingValue(Map<String, String> map, String key){
if(map.containsKey(key)){
return findCorrespondingValue(map, map.get(key));
}
return key;
}
As said the logic is very simple, we just check if for a given key
a value exists in the given map
- if yes we then execute the function again, but this time with the
value
as the newkey
. - if no mapping exists we can safely say that the
key
given is the last value in the chain
You can call the method like this:
Map<String, String> testMap = ... // setup testMap
Map<String, String> result = new HashMap<>();
for (final Entry<String, String> entry : testMap.entrySet()) {
result.put(
entry.getKey(),
findCorrespondingValue(testMap, entry.getValue())
);
}
or if you happend to use java 8:
Map<String, String> result = testMap.entrySet().stream()
.collect(Collectors.toMap(
e -> e.getKey(), // or just Map.Entry::getKey
e -> findCorrespondingValue(e.getValue())
));
You of course would have to implement some kind of logic to find out if you have cyclic references. E.g:
a -> b
b -> f
f -> a
Which would currently just fail with a StackOverflowError
.
You can make this also generic if you want to support multiple different types, not just String
:
public static <T> T findCorrespondingValue(Map<? extends T, ? extends T> map, T key){
if(map.containsKey(key)){
return findCorrespondingValue(map, map.get(key));
}
return key;
}