问题
I already know how to do it the hard way and got it working - iterating over entries and swapping "manually". But i wonder if, like so many tasks, this one can be solved in a more elegant way.
I have read this post, unfortunately it does not feature elegant solutions. I also have no possibility to use any fancy Guava BiMaps or anything outside the jdk (project stack is already defined).
I can assume that my map is bijective, btw :)
回答1:
The standard API / Java runtime doesn't offer a bi-directional map, so the only solution is to iterate over all entries and swap them manually.
What you can do is create a wrapper class which contains two maps and which does a dual put() internally so you have fast two views on the data.
[EDIT] Also, thanks to open source, you don't have to include a third party library, you can simply copy the classes you need into your own project.
回答2:
Map<String, Integer> map = new HashMap<>();
Map<Integer, String> swapped = map.entrySet().stream().collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey));
回答3:
If you don't have a choice to use a third party library, I don't consider the following code so ugly (though some scripting languages do have elegant ways of doing it):
//map must be a bijection in order for this to work properly
public static <K,V> HashMap<V,K> reverse(Map<K,V> map) {
HashMap<V,K> rev = new HashMap<V, K>();
for(Map.Entry<K,V> entry : map.entrySet())
rev.put(entry.getValue(), entry.getKey());
return rev;
}
回答4:
Maps are not like lists, which can be reversed by swapping head with tail.
Objects in maps have a computed position, and using the value as key and the key as value would requiere to re-compute the storage place, essentialy building another map. There is no elegant way.
There are, however, bidirectional maps. Those may suit your needs. I'd reconsider using third-party libraries.
回答5:
There are some jobs that can be simplified to a certain point and no more. This may be one of them!
If you want to do the job using Java collections apis only then brute force is the way to go - it will be quick (unless the collection is huge) and it will be an obvious piece of code.
回答6:
As a hint to answer https://stackoverflow.com/a/42091477/8594421
This only works, if the map is not a HashMap and does not contain duplicate values.
Map<String,String> newMap = oldMap.entrySet().stream().collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey));
throws an exception
java.lang.IllegalStateException: Duplicate key
if there are values more than once.
The solution:
HashMap<String,String> newMap = new HashMap<>();
for(Map.Entry<String,String> entry : oldMap.entrySet())
newMap.put(entry.getValue(), entry.getKey());
// Add inverse to old one
oldMap.putAll(newMap);
回答7:
If you had access to apache commons-collections, you could have used MapUtils.invertMap.
Note: The behaviour in case of duplicated values is undefined.
(Replying to this as this is the first google result for "java invert map").
回答8:
This will work for duplicate values in the map also, but not for HashMap as values.
package Sample;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class Sample {
public static void main(String[] args) {
Map<String,String> map = new HashMap<String,String>();
Map<String, Set<String> > newmap = new HashMap<String, Set<String> >();
map.put("1", "a");
map.put("2", "a");
map.put("3", "b");
map.put("4", "b");
System.out.println("before Reversing \n"+map.toString());
for (Map.Entry<String, String> entry : map.entrySet())
{
String oldVal = entry.getValue();
String oldKey = entry.getKey();
Set<String> newVal = null;
if (newmap.containsKey(oldVal))
{
newVal = newmap.get(oldVal);
newVal.add(oldKey);
}
else
{
newVal= new HashSet<>();
newVal.add(oldKey);
}
newmap.put(oldVal, newVal);
}
System.out.println("After Reversing \n "+newmap.toString());
}
}
来源:https://stackoverflow.com/questions/4436999/how-to-swap-keys-and-values-in-a-map-elegantly