Organizational Research By

Surprising Reserch Topic

sort a Map<Key, Value> on the values in Java?



asked Jun 22, 2015 in Core java by rahulgii
0 votes
106 views



Related Hot Questions

2 Answers

0 votes

Important added note: if you intend to use the code provided, be sure to read the comments as well to be aware of the implications. For example, values can no longer be retrieved by their key. (get always returns null.)

It seems much easier than all of the foregoing. Use a TreeMap as follows:

public class Testing {

    public static void main(String[] args) {

        HashMap map = new HashMap();
        ValueComparator bvc =  new ValueComparator(map);
        TreeMap sorted_map = new TreeMap(bvc);

        map.put("A",99.5);
        map.put("B",67.4);
        map.put("C",67.4);
        map.put("D",67.3);

        System.out.println("unsorted map: "+map);

        sorted_map.putAll(map);

        System.out.println("results: "+sorted_map);
    }
}

class ValueComparator implements Comparator {

    Map base;
    public ValueComparator(Map base) {
        this.base = base;
    }

    // Note: this comparator imposes orderings that are inconsistent with equals.    
    public int compare(String a, String b) {
        if (base.get(a) >= base.get(b)) {
            return -1;
        } else {
            return 1;
        } // returning 0 would merge keys
    }
}
Output:

    unsorted map: {D=67.3, A=99.5, B=67.4, C=67.4}
    results: {D=67.3, B=67.4, C=67.4, A=99.5}
    

answered Jun 22, 2015 by rahulgii
0 votes
Here's a generic-friendly version you're free to use:

import java.util.*;

public class MapUtil
{
    public static > Map
        sortByValue( Map map )
    {
        List> list =
            new LinkedList>( map.entrySet() );
        Collections.sort( list, new Comparator>()
        {
            public int compare( Map.Entry o1, Map.Entry o2 )
            {
                return (o1.getValue()).compareTo( o2.getValue() );
            }
        } );

        Map result = new LinkedHashMap();
        for (Map.Entry entry : list)
        {
            result.put( entry.getKey(), entry.getValue() );
        }
        return result;
    }
}
And an associated JUnit4 test so you don't have to take my word for it:

import java.util.*;
import org.junit.*;

public class MapUtilTest
{
    @Test
    public void testSortByValue()
    {
        Random random = new Random(System.currentTimeMillis());
        Map testMap = new HashMap(1000);
        for(int i = 0 ; i < 1000 ; ++i) {
            testMap.put( "SomeString" + random.nextInt(), random.nextInt());
        }

        testMap = MapUtil.sortByValue( testMap );
        Assert.assertEquals( 1000, testMap.size() );

        Integer previous = null;
        for(Map.Entry entry : testMap.entrySet()) {
            Assert.assertNotNull( entry.getValue() );
            if (previous != null) {
                Assert.assertTrue( entry.getValue() >= previous );
            }
            previous = entry.getValue();
        }
    }

}
Java 7 Version

public static > Map
    sortByValue( Map map )
{
    List> list =
        new LinkedList<>( map.entrySet() );
    Collections.sort( list, new Comparator>()
    {
        @Override
        public int compare( Map.Entry o1, Map.Entry o2 )
        {
            return (o1.getValue()).compareTo( o2.getValue() );
        }
    } );

    Map result = new LinkedHashMap<>();
    for (Map.Entry entry : list)
    {
        result.put( entry.getKey(), entry.getValue() );
    }
    return result;
}
Java 8 Version

public static > Map
    sortByValue( Map map )
{
      Map result = new LinkedHashMap<>();
     Stream > st = map.entrySet().stream();

     st.sorted(Comparator.comparing(e -> e.getValue()))
          .forEach(e ->result.put(e.getKey(),e.getValue()));

     return result;
}
answered Jun 22, 2015 by rahulgii

...