4

I want to sort a Map on key and value. First on key then on value. For example, this should be the result;

1,2 1,3 2,1 2,2

Anyone has a suggestion on how to achieve this effectively? I've been seeing people using a TreeMap to sort keys, however i also need values.

Or ofcouse any other method of sorting pairs on key and value is welcome.

ferdyh
  • 1,355
  • 2
  • 11
  • 29
  • The topmost related question seems to contain plenty of ideas. http://stackoverflow.com/questions/109383/how-to-sort-a-mapkey-value-on-the-values-in-java – Charles Goodwin Jul 01 '11 at 10:37
  • Do you mean some kind of 'multimap'? If you do, it's not in Java specifications. – bezmax Jul 01 '11 at 10:42

9 Answers9

7
import java.util.SortedSet;
import java.util.TreeSet;

public class SortMapOnKeyAndValue {

    public static void main(String[] args) {
        SortedSet<KeyValuePair> sortedSet = new TreeSet<KeyValuePair>();
        sortedSet.add(new KeyValuePair(1, 2));
        sortedSet.add(new KeyValuePair(2, 2));
        sortedSet.add(new KeyValuePair(1, 3));
        sortedSet.add(new KeyValuePair(2, 1));

        for (KeyValuePair keyValuePair : sortedSet) {
            System.out.println(keyValuePair.key+","+keyValuePair.value);
        }
    }
}
class KeyValuePair implements Comparable<KeyValuePair>{
    int key, value;

    public KeyValuePair(int key, int value) {
        super();
        this.key = key;
        this.value = value;
    }

    public int compareTo(KeyValuePair o) {
        return key==o.key?value-o.value:key-o.key;
    }
}
hd42
  • 1,741
  • 15
  • 30
3

What you are looking for a is SortedSetMultimap, part of Google's Guava library. The implementation they include is named TreeMultimap:
http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/collect/TreeMultimap.html

If you're not familiar with it, Guava is a fantastic library with lots of great stuff that you sometimes think should be in the standard Java libraries. I think Java 8, actually, will include some stuff from Guava (at least that seemed to me to be the drift of this item: http://openjdk.java.net/jeps/108).

1

Sounds like you want a multi map of some type e.g.

SortedMap<Key, SortedSet<Value>> map = new TreeMap<Key, SortedSet<Value>>();

map.put(1, new TreeSet<Integer>(Arrays.asList(1, 2)));
map.put(2, new TreeSet<Integer>(Arrays.asList(2, 1)));

System.out.println(map);

prints

{ 1 = {1, 2}, 2 = {1, 2}}
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
1

The other answers have indicated the problem with duplicate keys, but I am guessing you have pairs that you want to sort and the Map bit was just a mistake. The cleanest solution I can think of is to create a custom Pair class which implements Comparator and compares both the key and the value of two Pairs. You can then use Collections.sort to sort this.

manku
  • 1,268
  • 10
  • 9
0

Please follow this code :- This code will first sort the map by Key and then by value. Just write a main method and call this method as follow :-

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

public class SortMapByKeyAndValue
{
    public static void main(String[] args)
    {
        aMapSortProgramByKeyAndValue();
    }

    private static void aMapSortProgramByKeyAndValue()
    {
        Map<String, Integer> myMap = new HashMap<String, Integer>();
        // putting values in the Map
        myMap.put("Jayant", 80);
        myMap.put("Abhishek", 90);
        myMap.put("Anushka", 80);
        myMap.put("Amit", 75);
        myMap.put("Spandan", 50);
        myMap.put("Hari", 55);
        myMap.put("Keshav", 60);

        System.out.println("Map data without Sort :-");
        for (Entry<String, Integer> myEntryMapData : myMap.entrySet())
        {
            System.out.println("The Map data is Key: " + myEntryMapData.getKey() + " Value: "
                    + myEntryMapData.getValue());
        }

        List<Entry<String, Integer>> myMapDataAsList = new ArrayList<Map.Entry<String, Integer>>();
        myMapDataAsList.addAll(myMap.entrySet());

        System.out.println("Map data Stored in List, The whole List is : " + myMapDataAsList);

        Iterator<Entry<String, Integer>> myListIterator = myMapDataAsList.iterator();
        System.out.println("Map data Stored in List, Print through iterator :-");

        for (; myListIterator.hasNext();)
        {
            Entry<String, Integer> myListData = myListIterator.next();
            System.out.println("The List data is Key: " + myListData.getKey() + " Value: " + myListData.getValue());
        }

        Collections.sort(myMapDataAsList, new Comparator<Entry<String, Integer>>()
        {

            @Override
            public int compare(Entry<String, Integer> dataOne, Entry<String, Integer> dataTwo)
            {
                return dataOne.getKey().compareTo(dataTwo.getKey());
            }

        });

        System.out.println("After Sort by the Key the Map data is : ");
        myListIterator = myMapDataAsList.iterator();
        for (; myListIterator.hasNext();)
        {
            Entry<String, Integer> myListData = myListIterator.next();
            System.out.println("The List data is Key: " + myListData.getKey() + " Value: " + myListData.getValue());
        }

        Collections.sort(myMapDataAsList, new Comparator<Entry<String, Integer>>()
        {

            @Override
            public int compare(Entry<String, Integer> dataOne, Entry<String, Integer> dataTwo)
            {
                return dataOne.getValue().compareTo(dataTwo.getValue());
            }

        });

        System.out.println("After Sort by the vale the Map data is : ");
        myListIterator = myMapDataAsList.iterator();
        for (; myListIterator.hasNext();)
        {
            Entry<String, Integer> myListData = myListIterator.next();
            System.out.println("The List data is Key: " + myListData.getKey() + " Value: " + myListData.getValue());
        }
    }
}
Spandan
  • 11
  • 6
0

It is not possible, because a map cannot contain duplicate keys. A TreeMap is always sorted by key value (assuming, the key type is Comparable).


But for those task we usually take a map whose values are lists:

Map<Integer, List<Integer>> map = new TreeMap<Integer, List<Integer>>();

// add some values in random order
List<Integer> list = new ArrayList<Integer>();
list.add(2);
list.add(1);
map.put(2,list);
list = new ArrayList<Integer>();
list.add(2);
list.add(1);
map.put(1,list);

// result
for (Integer key:map.keySet()) {   // map is already sorted
  List<Integer> value = map.get(key);
  Collections.sort(value);         // list of values needs sorting
  for (Integer innerValue:value) {
    System.out.printf("%s : %s%n", key, innerValue);
  }
}
Andreas Dolk
  • 113,398
  • 19
  • 180
  • 268
0

If you are willing to take the risk, you could use the constructor that allows you to specify a Comparator: http://download.oracle.com/javase/1.5.0/docs/api/java/util/TreeMap.html#TreeMap%28java.util.Comparator%29

Having said that, what you want to do is ugly as hell and illegal because: * the order will not be consistent with equals(), which is a requisite for SortedSet) * the order may change due to altering values in the Map, and I don't know if its implementation allows for this.

I think that you need something else. Perhaps you would be better by creating an object that has both key and value and properly implements equals(), hashcode() and Comparable, and use a SortedSet with it.


EDIT: I have answered the generic question (sort a map on key and value) without looking at your samples. As others have written, you cannot have duplicate keys in a map.

SJuan76
  • 24,532
  • 6
  • 47
  • 87
0

The overall idea is, convert the Map into List, sort the List and put the sorted list back to a Map.

Map ---> List ---> Sort ---> Map

Example

import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

public class SortMyMap{

   public static void main(String[] args) {

    System.out.println("Unsort Map......");
    Map<String,String> unsortMap = new HashMap<String,String>();
    unsortMap.put("1", "1");
    unsortMap.put("2", "A");
    unsortMap.put("3", "2");

    Iterator iterator=unsortMap.entrySet().iterator();

        for (Map.Entry entry : unsortMap.entrySet()) {
            System.out.println("Key : " + entry.getKey() 
                + " Value : " + entry.getValue());
        }

        System.out.println("Sorted Map......");
        Map<String,String> sortedMap =  sortByComparator(unsortMap);

        for (Map.Entry entry : sortedMap.entrySet()) {
            System.out.println("Key : " + entry.getKey() 
                + " Value : " + entry.getValue());
        }
   }

   private static Map sortByComparator(Map unsortMap) {

        List list = new LinkedList(unsortMap.entrySet());

        //sort list based on comparator
        Collections.sort(list, new Comparator() {
             public int compare(Object o1, Object o2) {
               return ((Comparable) ((Map.Entry) (o1)).getValue())
               .compareTo(((Map.Entry) (o2)).getValue());
             }
    });

        //put sorted list into map again
    Map sortedMap = new LinkedHashMap();
    for (Iterator it = list.iterator(); it.hasNext();) {
         Map.Entry entry = (Map.Entry)it.next();
         sortedMap.put(entry.getKey(), entry.getValue());
    }
    return sortedMap;
   }    
}
Sunil Kumar Sahoo
  • 53,011
  • 55
  • 178
  • 243
-1

you can't have such map

 1->11
 1->21

the key '1' is common so 21 will replace 11

Penkov Vladimir
  • 921
  • 5
  • 10