Java 中的反向 HashMap 键和值

这是个简单的问题, 我有一个简单的 HashMap,我想反转它的键和值。

HashMap<Character, String> myHashMap = new HashMap<Character, String>();
myHashMap.put('a', "test one");
myHashMap.put('b', "test two");

我想创建一个新的 HashMap 把对立面放进去。

HashMap<String, Character> reversedHashMap = new HashMap<String, Character>();
e.g. Keys "test one" & "test two" and values 'a' & 'b'.
142295 次浏览

Iterate through the list of keys and values, then add them.

HashMap<String, Character> reversedHashMap = new HashMap<String, Character>();
for (String key : myHashMap.keySet()){
reversedHashMap.put(myHashMap.get(key), key);
}

They all are unique, yes

If you're sure that your values are unique you can iterate over the entries of your old map .

Map<String, Character> myNewHashMap = new HashMap<>();
for(Map.Entry<Character, String> entry : myHashMap.entrySet()){
myNewHashMap.put(entry.getValue(), entry.getKey());
}

Alternatively, you can use a Bi-Directional map like Guava provides and use the inverse() method :

BiMap<Character, String> myBiMap = HashBiMap.create();
myBiMap.put('a', "test one");
myBiMap.put('b', "test two");


BiMap<String, Character> myBiMapInversed = myBiMap.inverse();

As is out, you can also do it this way :

Map<String, Integer> map = new HashMap<>();
map.put("a",1);
map.put("b",2);


Map<Integer, String> mapInversed =
map.entrySet()
.stream()
.collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey))

Finally, I added my contribution to the proton pack library, which contains utility methods for the Stream API. With that you could do it like this:

Map<Character, String> mapInversed = MapStream.of(map).inverseMapping().collect();

To answer your question on how you can do it, you could get the entrySet from your map and then just put into the new map by using getValue as key and getKey as value.

But remember that keys in a Map are unique, which means if you have one value with two different key in your original map, only the second key (in iteration order) will be kep as value in the new map.

I wrote a simpler loop that works too (note that all my values are unique):

HashMap<Character, String> myHashMap = new HashMap<Character, String>();
HashMap<String, Character> reversedHashMap = new HashMap<String, Character>();


for (char i : myHashMap.keySet()) {
reversedHashMap.put(myHashMap.get(i), i);
}

Apache commons collections library provides a utility method for inversing the map. You can use this if you are sure that the values of myHashMap are unique

org.apache.commons.collections.MapUtils.invertMap(java.util.Map map)

Sample code

HashMap<String, Character> reversedHashMap = MapUtils.invertMap(myHashMap)
private <A, B> Map<B, A> invertMap(Map<A, B> map) {
Map<B, A> reverseMap = new HashMap<>();
for (Map.Entry<A, B> entry : map.entrySet()) {
reverseMap.put(entry.getValue(), entry.getKey());
}
return reverseMap;
}

It's important to remember that put replaces the value when called with the same key. So if you map has two keys with the same value only one of them will exist in the inverted map.

If the values are not unique, the safe way to inverse the map is by using java 8's groupingBy function

Map<String, Integer> map = new HashMap<>();
map.put("a",1);
map.put("b",2);


Map<Integer, List<String>> mapInversed =
map.entrySet()
.stream()
.collect(Collectors.groupingBy(Map.Entry::getValue, Collectors.mapping(Map.Entry::getKey, Collectors.toList())))

Tested with below sample snippet, tried with MapUtils, and Java8 Stream feature. It worked with both cases.

public static void main(String[] args) {
Map<String, String> test = new HashMap<String, String>();
test.put("a", "1");
test.put("d", "1");
test.put("b", "2");
test.put("c", "3");
test.put("d", "4");
test.put("d", "41");


System.out.println(test);


Map<String, String> test1 = MapUtils.invertMap(test);


System.out.println(test1);


Map<String, String> mapInversed =
test.entrySet()
.stream()
.collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey));


System.out.println(mapInversed);
}


Output:
{a=1, b=2, c=3, d=41}
{1=a, 2=b, 3=c, 41=d}
{1=a, 2=b, 3=c, 41=d}

For Reversing the Array of Dictionary. (If values are Unique)

private void reverseArrayMap(List<Map<String, String>> list) {
// reversing the array of dictionary
List<Map<String, String>> newList = new ArrayList<>();
Map<String, String> resDic = new HashMap<>();


for (Map<String, String> map : list) {
map.forEach((key, value) -> resDic.put(value, key));
newList.add(resDic);
}


System.out.println("Original Array of Dictionary" + list);
System.out.println("Reversed Array of Dictionary" + newList);
}

for reverting the map, in your case:

private void reverseMap(Map<Character, String> map) {
Map<String, Character> newList = new HashMap<>();
map.forEach((key, value) -> newList.put(value, key));
System.out.println(newList);
}

or you can traverse the old hashmap

HashMap<String, Character> newList = new HashMap<String, Character>();
for (String key : list.keySet()){
newList.put(list.get(key), key);
}

Use forEach introduced in Java 8

Map<Short, String> regularMap = new HashMap<>();
Map<String, Short> inversedMap = new HashMap<>();


regularMap.forEach((key, value) -> inversedMap.put(value, key));

Java :
Simple approach, No need for java 8

Map<String,String> map=new HashMap<>();
Map<String,String> mapInv=new HashMap<>();


for (String key : map.keySet())
mapInv.put(map.get(key), key);

Java 8:
forEach() is a new method to iterate the elements. It is defined in Iterable and Stream interface.

Map<String,String> map=new HashMap<>();
Map<String,String> mapInv=new HashMap<>();


map.forEach((key, value) -> mapInv.put(value, key));

Kotlin :

    val map: Map<String, String> = HashMap()
val mapInv: MutableMap<String?, String> = HashMap()


for (key in map.keys) mapInv[map[key]] = key