1

I have a HashMap defined as follows

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

I am then storing data from databse in this hashmap and displaying the contents as follows on the console where entries towards the left of ---> are ID's and entries towards right are tags used by this ID

165767--->[dual-boot, windows, uninstall, ati, graphics, multiple-monitors]
6873 --->[kubuntu, re-installation]
34228--->[11.10, unity, launcher, libreoffice, icons]

I want to sort the ID's in descending order based on the number of tags that they have used i.e. based on map.get(key).size() so that the output should be ID 165767 followed by 34228 and then 6873 and so on.

I tried doing it with TreeMap but I am not able to figure out how to do it based on size and not the value of key and that too in descending order.

user2916886
  • 847
  • 2
  • 16
  • 35
  • possible duplicate of [Sorting hashmap by values](http://stackoverflow.com/questions/8119366/sorting-hashmap-by-values). Plus, you will need a comparator that compares the lists based on their length. – Jim Garrison Nov 09 '13 at 20:35
  • Can you build the map first and then sort afterwards? – Alan Stokes Nov 09 '13 at 21:07
  • Or ... how about obtain your data already sorted from your database that you can simply translate into a HashMap? You ought to be able to do this with SQL. – scottb Nov 09 '13 at 21:49
  • @scottb, I don't think that is preferable, and even if it is, that will only work if is a `LinkedHashMap`, since `HashMap` does not maintain order. – Paul Draper Nov 09 '13 at 22:44
  • @scottb, bringing sorted data from database was not possible because the format of data present in database cannot be sorted.I am doing a lot of preprocessing before this to first clean the data after it is extracted from database and then using HashMap. – user2916886 Nov 09 '13 at 22:55

3 Answers3

3

This creates a sorted list of ids.

List<String> sortedIds = new ArrayList<String>(map.getKeys());
Collections.sort(sortedIds, new Comparator<String>() {
    public int compare(String a, String b) {
        return map.get(b).size() - map.get(a).size();
    }
});

Not that you would never to maintain a SortedMap (like TreeMap), sorted on mutable values (like the length of an ArrayList). Since the sorted order is used to look up values, it could cause very big problems if "id123" became greater than "id456" without the Collection knowing about it.

Paul Draper
  • 78,542
  • 46
  • 206
  • 285
0

EDIT :

My output should be sorted based on number of tags and not the size of ID

Map<String, ArrayList<String>>  map = new TreeMap<String, ArrayList<String>>();


map.put("165767",new ArrayList<String>(Arrays.asList("dual-boot", "dual-boot", "windows", "uninstall", "ati", "graphics", "multiple-monitors")));
map.put("6873",new ArrayList<String>(Arrays.asList("kubuntu", "kubuntu", "re-installation")));
map.put("0000000000000000",new ArrayList<String>(Arrays.asList("test","test", "test")));
map.put("0125",new ArrayList<String>(Arrays.asList("dual-boot", "windows", "uninstall", "ati", "graphics", "multiple-monitors")));


for(ArrayList<String> l : map.values()){
    Set<String> hs = new HashSet<>();
    hs.addAll(l);
    l.clear();
    l.addAll(hs);
}

List<ArrayList<String>> l = new ArrayList<>(map.values());
Collections.sort(l, new Comparator<ArrayList<String>>(){
    public int compare(ArrayList<String> s1, ArrayList<String> s2){
        return Integer.compare(s2.size(), s1.size());                
    }});

for(ArrayList<String> a : l){
    Iterator<Entry<String, ArrayList<String>>> iter = map.entrySet().iterator();
    while (iter.hasNext()) {
        Entry<String, ArrayList<String>> e = iter.next();
        if(e.getValue().equals(a)){

            System.out.println(e.getKey() + "-" + a);
            iter.remove();
        }
    }
}

Output :

0125-[uninstall, dual-boot, graphics, windows, ati, multiple-monitors]
165767-[uninstall, dual-boot, graphics, windows, ati, multiple-monitors]
6873-[re-installation, kubuntu]
0000000000000000-[test]
Alexis C.
  • 91,686
  • 21
  • 171
  • 177
  • I think you misunderstood the question.My output should be sorted based on number of tags and not the size of ID.Your output looks like it is sorting based on size of ID. – user2916886 Nov 09 '13 at 21:02
  • yes that is what I was looking for.Thanks for help.Just a little more favour.Suppose if my Tags have possible duplicates.How can I remove them from final display? – user2916886 Nov 09 '13 at 21:52
  • @user2916886 In my example, there is a duplicate Tags. Not sure if I answered your question or not... – Alexis C. Nov 09 '13 at 21:54
  • What I meant was suppose if Id 6873 has Tags list as[kubuntu,re-installation,kubuntu] then how can I remove the extra 'kubuntu' here i.e. duplicate tag in each array list – user2916886 Nov 09 '13 at 22:04
  • @user2916886 Check my edit. Basically, you can add the elements to an hashSet which doesn't allow duplicates and then clear the arrayList and re-add the elements of the hashset to this arrayList. – Alexis C. Nov 09 '13 at 22:10
  • Thanks a lot!It works perfectly.Just one question.The iter.remove() in your code is the one which clears the arraylist? – user2916886 Nov 09 '13 at 22:22
  • Nop its remove the corresponding key value pair to the map. – Alexis C. Nov 09 '13 at 22:25
0

I had a similar scenario and this code worked for me (sometimes I have nulls):

     private static Map<Object,List<Object>> sortByArraySizeDesc(Map<Object,List<Object>> map) {
         List<List<Object>> list = new LinkedList(map.entrySet());
         Collections.sort(list, new Comparator() {
              public int compare(Object o1, Object o2) { 
                  if (o1 == null && o2 == null) { return 0; }
                  else if (o1 == null) { return 1;}
                  else if (o2 == null) { return -1; }
                  int size1 = ((List) ((Map.Entry) (o1)).getValue()).size();
                  int size2 = ((List) ((Map.Entry) (o2)).getValue()).size();
                  return size2 - size1;
              }
         });

        Map res = new LinkedHashMap();
        for (Iterator it = list.iterator(); it.hasNext();) {
            Map.Entry entry = (Map.Entry)it.next();
            res.put(entry.getKey(), entry.getValue());
        }
        return res;
    } 
Michail Michailidis
  • 11,792
  • 6
  • 63
  • 106