How to swap keys and values in a Map elegantly

前端 未结 8 1864
滥情空心
滥情空心 2020-12-25 14:49

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

相关标签:
8条回答
  • 2020-12-25 15:00

    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;
    }
    
    0 讨论(0)
  • 2020-12-25 15:01

    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()); 
        } 
    }
    
    0 讨论(0)
  • 2020-12-25 15:04

    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);
    
    0 讨论(0)
  • 2020-12-25 15:05

    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.

    0 讨论(0)
  • 2020-12-25 15:07

    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.

    0 讨论(0)
  • 2020-12-25 15:09

    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.

    0 讨论(0)
提交回复
热议问题