Inverting a Map In Java

This Java tutorial will teach us how to invert a given Map using different techniques. We will learn to invert Maps with unique values and create Multimap when there are duplicate values.

1. What is an Inverted Map?

An inverted Map <V, K> is an instance of the original Map<K, V>. The values of the original map become keys in the resulting map, and the keys become values.

Map<String, String> map = Map.of("key1", "value1", "key2", "value2");
System.out.println(map);   //{key1=value1, key2=value2}

//Inverted Map entries
{value1=key1, value2=key2}

2. Inverting Map with Unique Values

The following approaches should be used to invert a map containing unique values because we are not employing any mechanism to resolve duplicate keys/values.

2.1. Using for-Loop

The easiest way to invert a map is by using a loop. We iterate through the entries of the map and add them to a new Map. While adding entries, we interchange the keys and values with each other.

Map<Integer, String> invertedMap = new HashMap<>();

for (Map.Entry<String, Integer> entry : originalMap.entrySet()) {
  invertedMap.put(entry.getValue(), entry.getKey());
}

2.2. Using Collectors.toMap()

Stream API provides Collectors.toMap() to conveniently collect Stream elements into a Map. We need to iterate over the Stream elements and collect the entries in inverse order.

Map<Integer, String> inverseMap = originalMap.entrySet()
        .stream()
        .collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey));

3. Inverting Map with Duplicate Values

Suppose the Map has few entries with duplicate values. Now when inversing the Map, we must decide how to handle these values because inversed Map will not allow duplicate keys.

Generally, creating a MultiMap is the right solution for these cases. MultiMap is similar to a Map with the addition that multiple elements can have the same keys.

3.1. Using for-Loop

In the following example, a List is used to store the multiple values for a key, resulting in a multimap.

Map<Integer, String> mapWithDuplicateValues = new HashMap<Integer, String>();
mapWithDuplicateValues.put(1, "Value1");
mapWithDuplicateValues.put(2, "Value2");
mapWithDuplicateValues.put(3, "Value2");

HashMap<String, List<Integer>> inverseMap = new HashMap<String, List<Integer>>();

for (Map.Entry<Integer, String> entry : mapWithDuplicateValues.entrySet()) {
  if (inverseMap.containsKey(entry.getValue())) {
    inverseMap.get(entry.getValue()).add(entry.getKey());
  } else {
    List<Integer> list = new ArrayList<Integer>();
    list.add(entry.getKey());
    inverseMap.put(entry.getValue(), list);
  }
}
System.out.println(inverseMap);   //{Value1=[1], Value2=[2, 3]}

3.2. Using Collectors.groupBy()

In the following example, Collectors.mapping() function performs the reduction operation on the duplicate values by passing to the collector which is used to collect the duplicate values into a List.

HashMap<String, List<Integer>> inverseMap = originalMap.entrySet()
      .stream()
      .collect(Collectors.groupingBy(Entry::getValue,
              Collectors.mapping(Entry::getKey, Collectors.toList())));

4. Using Guava Library

Guava is an open-source Java library which is created by Google. It provides numerous useful collections and interfaces. We will use the following maps to invert a given map.

4.1. Using Multimap

The Multimap is a straightforward implementation and internally manages the duplicate values.

Multimap<Integer, String> multimap = ImmutableMultimap.of(1, "Key1", 1, "Key2", 2, "Key3");

System.out.println(multimap); //{1=[Key1, Key2], 2=[Key3]}

4.2. Using BiMap

A BiMap is a bidirectional map that maintains an inverse view of the map i.e entries with reversed keys and values. This map also maintains that no duplicate values or keys are stored in the map.

BiMap<Integer, String> biMap = ImmutableBiMap.of(1, "Key1", 2, "Key2", 3, "Key3");
BiMap<String, Integer> inverseBiMap = biMap.inverse();

System.out.println(inverseBiMap); //{Key1=1, Key2=2, Key3=3}

There is another class HashBiMap backed by two hash tables, one for the key to value mapping and the other for value to key mapping. This implementation allows null keys and values.

BiMap<Integer,String> originalMap = HashBiMap.create();
//add key-value pairs

BiMap<String, Integer> inversedMap = biMap.inverse();

5. Using Apache Commons-Collections

Apache commons collections library offers various implementations and utilities to facilitate collection handling easily. We will use the BidiMap and inverseBidiMap() methods for inverting the map, very much like we did for Guava.

5.1. Using BidiMap

The BidiMap interface allows the bidirectional lookup between the keys and values. Here are the different implementations of this interface:

  • DualHashBidiMap: It uses two HashMap instances which provide a fast lookup of entries using key or value
  • DualLinkedHashBidiMap: It uses two LinkedHashMap instances which provide fast lookup at the expense of storing two sets of linked lists and map entries.
  • TreeBidiMap: This map is based on the Red-Black tree implementation. It assures that the keys-values will be stored in an ascending manner according to the natural ordering of keys & values.
  • DualTreeBidiMap: It uses the two TreeMap instances making it more expensive than TreeBidiMap as it stores each object twice.

We can use the inverseBidiMap() method to get the inverted view of the original map. Note that when duplicate values are found the later key takes precedence over the previous one.

BidiMap bidiMap = new DualHashBidiMap();
bidiMap.put(1, "Value1");
bidiMap.put(2, "Value2");

System.out.println(bidiMap.inverseBidiMap());         //{Value1=1, Value2=2}  

5.2. Using MapUtils.invertMap() 

The invertMap() method returns a new HashMap in which keys and values are swapped. Note that if the original map has duplicate values for multiple keys, the returned map will contain one of those keys, but the exact key which should be mapped will be undefined.

Map<Integer, String> hashMap = new HashMap<Integer, String>();
hashMap.put(1,"Value1");
hashMap.put(2,"Value2");
hashMap.put(3,"Value2");

Map<String,Integer> inversedMap1 = MapUtils.invertMap(hashMap);
System.out.println(inversedMap1);  //{Value1=1, Value2=3}

6. Conclusion

In this Java tutorial, we learned to invert a specified Map using different techniques from for-loop to Guava and Apache-collections methods. We also inverted maps with duplicate values. The efficient way to reverse a given map is by using external libraries like Guava or Apache-commons instead of iterating over the entries.

Happy Learning !!

Sourcecode on Github

Comments

Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.

Our Blogs

REST API Tutorial

Dark Mode

Dark Mode