127

How are we able to sort a HashMap<key, ArrayList>?

I want to sort on the basis of a value in the ArrayList.

MC Emperor
  • 22,334
  • 15
  • 80
  • 130

17 Answers17

149

Do you have to use a HashMap? If you only need the Map Interface use a TreeMap


If you want to sort by comparing values in the HashMap. You have to write code to do this, if you want to do it once you can sort the values of your HashMap:

Map<String, Person> people = new HashMap<>();
Person jim = new Person("Jim", 25);
Person scott = new Person("Scott", 28);
Person anna = new Person("Anna", 23);

people.put(jim.getName(), jim);
people.put(scott.getName(), scott);
people.put(anna.getName(), anna);

// not yet sorted
List<Person> peopleByAge = new ArrayList<>(people.values());

Collections.sort(peopleByAge, Comparator.comparing(Person::getAge));

for (Person p : peopleByAge) {
    System.out.println(p.getName() + "\t" + p.getAge());
}

If you want to access this sorted list often, then you could insert your elements into a HashMap<TreeSet<Person>>, though the semantics of sets and lists are a bit different.

Michael
  • 41,989
  • 11
  • 82
  • 128
pgras
  • 12,614
  • 4
  • 38
  • 46
  • 2
    A few more points: First, there are two decisions you need to make: (1) Whether you want to sort by the values, or by the keys, (2) Whether you have control over the collection at the start, so you can use built-in sorting, vs. when you're handed existing Maps and just want to iterate through them in some order. Also, the LinkedHashMap can maintain by insertion order (which I often like for debugging), or by access order. And finally if you're doing a lot of this you might check out Java 1.6 and [NavigableMap](http://java.sun.com/javase/6/docs/api/java/util/NavigableMap.html), awesome stuff! – Mark Bennett Jan 05 '12 at 00:58
  • 2
    If you want to sort by keys use a SortedMap instead. It gives you automatic sorted keys. – Marquinho Peli Nov 03 '16 at 16:01
  • TreeMap was the answer I was looking for when I came here so thank you. – vedi0boy Jul 27 '17 at 13:36
  • `TreeMap` seems like a really poor choice of name for the class... should be something like `SortedMap` instead. From the name, I'd think it's not a `Map` at all but some kind of `Tree`... the `Tree` part of `TreeMap` is really more of an implementation detail that shouldn't concern the user of the class at all. – ArtOfWarfare Oct 13 '17 at 13:33
  • @ArtOfWarfare: Exactly the `Tree` **is** an implementation detail and therefore should concern the user when he chooses which class to use to implement the `SortedMap` interface... – pgras Oct 13 '17 at 14:09
39

Sorted List by hasmap keys:

SortedSet<String> keys = new TreeSet<String>(myHashMap.keySet());

Sorted List by hashmap values:

SortedSet<String> values = new TreeSet<String>(myHashMap.values());

In case of duplicated map values:

List<String> mapValues = new ArrayList<String>(myHashMap.values());
Collections.sort(mapValues);

Good Luck!

gokhansari
  • 2,379
  • 1
  • 27
  • 33
24

http://snipplr.com/view/2789/sorting-map-keys-by-comparing-its-values/

get the keys

List keys = new ArrayList(yourMap.keySet());

Sort them

 Collections.sort(keys)

print them.

In any case, you can't have sorted values in HashMap (according to API This class makes no guarantees as to the order of the map; in particular, it does not guarantee that the order will remain constant over time ].

Though you can push all these values to LinkedHashMap, for later use as well.

rogerdpack
  • 62,887
  • 36
  • 269
  • 388
13

Seems like you might want a treemap.

http://docs.oracle.com/javase/7/docs/api/java/util/TreeMap.html

You can pass in a custom comparator to it if that applies.

Ben Pearson
  • 7,532
  • 4
  • 30
  • 50
JH.
  • 4,147
  • 3
  • 19
  • 20
12

In Java 8:

Comparator<Entry<String, Item>> valueComparator = 
    (e1, e2) -> e1.getValue().getField().compareTo(e2.getValue().getField());

Map<String, Item> sortedMap = 
    unsortedMap.entrySet().stream().
    sorted(valueComparator).
    collect(Collectors.toMap(Entry::getKey, Entry::getValue,
                             (e1, e2) -> e1, LinkedHashMap::new));

Using Guava:

Map<String, Item> map = ...;
Function<Item, Integer> getField = new Function<Item, Integer>() {
    public Integer apply(Item item) {
        return item.getField(); // the field to sort on
    }
};
comparatorFunction = Functions.compose(getField, Functions.forMap(map));
comparator = Ordering.natural().onResultOf(comparatorFunction);
Map<String, Item> sortedMap = ImmutableSortedMap.copyOf(map, comparator);
Vitalii Fedorenko
  • 110,878
  • 29
  • 149
  • 111
  • 1
    Why must we add a new library to perform a function that could be available natively? – MAbraham1 Nov 26 '13 at 16:10
  • Java 8 comparator can be rewritten as: `Comparator> valueComparator = Comparator.comparing(Map.Entry::getValue().getField());` – Mathias G. Apr 18 '17 at 07:35
9

Custom compare function which includes functionality for the Turkish alphabet or other different languages than english.

public <K extends Comparable,V extends Comparable> LinkedHashMap<K,V> sortByKeys(LinkedHashMap<K,V> map){
    List<K> keys = new LinkedList<K>(map.keySet());
    Collections.sort(keys, (Comparator<? super K>) new Comparator<String>() {
        @Override
        public int compare(String first, String second) {
            Collator collator = Collator.getInstance(Locale.getDefault());
            //Collator collator = Collator.getInstance(new Locale("tr", "TR"));
            return collator.compare(first, second);
        }
    });

    LinkedHashMap<K,V> sortedMap = new LinkedHashMap<K,V>();
    for(K key: keys){
        sortedMap.put(key, map.get(key));
    }

    return sortedMap;
}

here is the using example as the following

LinkedHashMap<String, Boolean> ligList = new LinkedHashMap<String, Boolean>();
ligList = sortByKeys(ligList);
Mustafa Güven
  • 15,526
  • 11
  • 63
  • 83
4

Without any more information, it's hard to know exactly what you want. However, when choosing what data structure to use, you need to take into account what you need it for. Hashmaps are not designed for sorting - they are designed for easy retrieval. So in your case, you'd probably have to extract each element from the hashmap, and put them into a data structure more conducive to sorting, such as a heap or a set, and then sort them there.

Smashery
  • 57,848
  • 30
  • 97
  • 128
  • actually its not for sorting the hash map is used for storing data read from file and its values –  Apr 23 '09 at 06:55
  • we have to sort only based on one element of the array list in the hash map hashmap map –  Apr 23 '09 at 06:58
  • Yeah, it sounds like what you want is what the other guys are saying - TreeMap. TreeMaps seem much like HashMaps, except you can also sort them. Hooray! – Smashery Apr 23 '09 at 07:03
  • if we are storing in the hash map(key,person) person is a class its having four objects if we want sort based one one of the objects how we will do that...? –  Apr 23 '09 at 07:11
3

have you considered using a LinkedHashMap<>()..?

  public static void main(String[] args) {
    Map<Object, Object> handler = new LinkedHashMap<Object, Object>();
    handler.put("item", "Value");
    handler.put(2, "Movies");
    handler.put("isAlive", true);

    for (Map.Entry<Object, Object> entrY : handler.entrySet())
        System.out.println(entrY.getKey() + ">>" + entrY.getValue());

    List<Map.Entry<String, Integer>> entries = new ArrayList<Map.Entry<String, Integer>>();
    Collections.sort(entries, new Comparator<Map.Entry<String, Integer>>() {
        public int compare(Map.Entry<String, Integer> a,
                Map.Entry<String, Integer> b) {
            return a.getValue().compareTo(b.getValue());
        }
    });
}

results into an organized linked object.

 item>>Value
 2>>Movies
 isAlive>>true

check the sorting part picked from here..

Zuko
  • 2,764
  • 30
  • 30
3

I have developed a class which can be used to sort a map on the basis of keys and values. The basic idea is if you have sort a map using keys then create a TreepMap from your Map which will sort the map by keys. And in case of sorting by values create a list from entrySet and sort the list using comparator interface.

Here is the full solution :

public static void main(String[] args) {
    Map<String, Integer> unSortedMap = new LinkedHashMap<String, Integer>();
    unSortedMap.put("A", 2);
    unSortedMap.put("V", 1);
    unSortedMap.put("G", 5);
    System.out.println("Unsorted Map :\n");
    for (Map.Entry<String, Integer> entry : unSortedMap.entrySet()) {
        System.out.println(entry.getKey() + "   " + entry.getValue());
    }
    System.out.println("\n");
    System.out.println("Sorting Map Based on Keys :\n");
    Map<String, Integer> keySortedMap = new TreeMap<String, Integer>(unSortedMap);
    for (Map.Entry<String, Integer> entry : keySortedMap.entrySet()) {
        System.out.println(entry.getKey() + "   " + entry.getValue());
    }
    System.out.println("\n");
    System.out.println("Sorting Map Based on Values :\n");
    List<Entry<String, Integer>> entryList = new ArrayList<Entry<String, Integer>>(unSortedMap.entrySet());
    Collections.sort(entryList, new Comparator<Entry<String, Integer>>() {

        @Override
        public int compare(Entry<String, Integer> obj1, Entry<String, Integer> obj2) {
            return obj1.getValue().compareTo(obj2.getValue());
        }
    });
    unSortedMap.clear();
    for (Entry<String, Integer> entry : entryList) {
        unSortedMap.put(entry.getKey(), entry.getValue());
        System.out.println(entry.getKey() + "   " + entry.getValue());
    }
}

Code is properly tested :D

  • This isn't really a _class_. Also, your sorted values are stored in *entryList*, why are you clearing *unSortedMap* and printing it again? I suggest making a method named something like _sortMap_ that has _unSortedMap_ as param and returns _entryList_. – Buffalo May 10 '18 at 06:34
3

If you want to combine a Map for efficient retrieval with a SortedMap, you may use the ConcurrentSkipListMap.

Of course, you need the key to be the value used for sorting.

2

Sorting HashMap by Value:

As others have pointed out. HashMaps are for easy lookups if you change that or try to sort inside the map itself you will no longer have O(1) lookup.

The code for your sorting is as follows:

class Obj implements Comparable<Obj>{
    String key;
    ArrayList<Integer> val;
    Obj(String key, ArrayList<Integer> val)
    {
    this.key=key;
    this.val=val;
    }
    public int compareTo(Obj o)
    {
     /* Write your sorting logic here. 
     this.val compared to o.val*/
     return 0;
    }
}

public void sortByValue(Map<String, ArrayList<>> mp){

    ArrayList<Obj> arr=new ArrayList<Obj>();
    for(String z:mp.keySet())//Make an object and store your map into the arrayList
    {

        Obj o=new Obj(z,mp.get(z));
        arr.add(o);
    }
    System.out.println(arr);//Unsorted
    Collections.sort(arr);// This sorts based on the conditions you coded in the compareTo function.
    System.out.println(arr);//Sorted
}
Anuj Mehta
  • 31
  • 2
2

A proper answer.

HashMap<Integer, Object> map = new HashMap<Integer, Object>();

ArrayList<Integer> sortedKeys = new ArrayList<Integer>(map.keySet());
Collections.sort(sortedKeys, new Comparator<Integer>() {
  @Override
  public int compare(Integer a, Integer b) {
    return a.compareTo(b);
  }
});

for (Integer key: sortedKeys) {
  //map.get(key);
}

Note that HashMap itself cannot maintain sorting, as other answers have pointed out. It's a hash map, and hashed values are unsorted. You can thus either sort the keys when you need to and then access the values in order, as I demonstrated above, or you can find a different collection to store your data, like an ArrayList of Pairs/Tuples, such as the Pair found in Apache Commons:

https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/tuple/Pair.html

Andrew
  • 5,839
  • 1
  • 51
  • 72
1

Sorting by key:

public static void main(String[] args) {
    Map<String,String> map = new HashMap<>();

    map.put("b", "dd");
    map.put("c", "cc");
    map.put("a", "aa");

    map = new TreeMap<>(map);

    for (String key : map.keySet()) {
        System.out.println(key+"="+map.get(key));
    }
}
ssoo
  • 19
  • 2
  • but we aren't providing anything to specify ascending/descending and sort by value. – Constantine1991 Jun 25 '19 at 21:57
  • This is misleading because tree map does the sorting based on keys not value. Please updated the use cases for TreeMap because it cannot be applied everywhere. – Agent 0 Aug 01 '23 at 20:56
0

I developed a fully tested working solution. Hope it helps

import java.io.BufferedReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.StringTokenizer;


public class Main {
    public static void main(String[] args) {
    try {
        BufferedReader in = new BufferedReader(new java.io.InputStreamReader           (System.in));
            String str;

        HashMap<Integer, Business> hm = new HashMap<Integer, Business>();
        Main m = new Main();


        while ((str = in.readLine()) != null) {


            StringTokenizer st = new StringTokenizer(str);
            int id = Integer.parseInt(st.nextToken());    // first integer
            int rating = Integer.parseInt(st.nextToken());    // second 

            Business a = m.new Business(id, rating);


            hm.put(id, a);


            List<Business> ranking = new ArrayList<Business>(hm.values());

            Collections.sort(ranking, new Comparator<Business>() {

                public int compare(Business i1, Business i2) {
                    return i2.getRating() - i1.getRating();
                }
            });

            for (int k=0;k<ranking.size();k++) {
                System.out.println((ranking.get(k).getId() + " " + (ranking.get(k)).getRating()));
            }


        }
        in.close();

    } catch (IOException e) {
        e.printStackTrace();
    }


}
public class Business{

    Integer id;
    Integer rating;

    public Business(int id2, int rating2)
    {
        id=id2;
        rating=rating2;

    }

    public Integer getId()
    {
        return id;
    }
    public Integer getRating()
    {
        return rating;
    }


}
}
danywarner
  • 928
  • 2
  • 15
  • 28
0

HashMap doesnt maintain any order, so if you want any kind of ordering, you need to store that in something else, which is a map and can have some kind of ordering, like LinkedHashMap

below is a simple program, by which you can sort by key, value, ascending ,descending ..( if you modify the compactor, you can use any kind of ordering, on keys and values)

package com.edge.collection.map;

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

public class SortMapByKeyValue {
Map<String, Integer> map = new HashMap<String, Integer>();

public static void main(String[] args) {

    SortMapByKeyValue smkv = new SortMapByKeyValue();
    smkv.createMap();

    System.out.println("After sorting by key ascending order......");
    smkv.sortByKey(true);

    System.out.println("After sorting by key descindeng order......");
    smkv.sortByKey(false);

    System.out.println("After sorting by value ascending order......");
    smkv.sortByValue(true);

    System.out.println("After sorting by value  descindeng order......");
    smkv.sortByValue(false);

}

void createMap() {
    map.put("B", 55);
    map.put("A", 80);
    map.put("D", 20);
    map.put("C", 70);
    map.put("AC", 70);
    map.put("BC", 70);
    System.out.println("Before sorting......");
    printMap(map);
}

void sortByValue(boolean order) {

    List<Entry<String, Integer>> list = new LinkedList<Entry<String, Integer>>(map.entrySet());
    Collections.sort(list, new Comparator<Entry<String, Integer>>() {
        public int compare(Entry<String, Integer> o1, Entry<String, Integer> o2) {
            if (order) {
                return o1.getValue().compareTo(o2.getValue());
            } else {
                return o2.getValue().compareTo(o1.getValue());

            }
        }
    });
    Map<String, Integer> sortedMap = new LinkedHashMap<String, Integer>();
    for (Entry<String, Integer> entry : list) {
        sortedMap.put(entry.getKey(), entry.getValue());
    }
    printMap(sortedMap);

}

void sortByKey(boolean order) {

    List<Entry<String, Integer>> list = new LinkedList<Entry<String, Integer>>(map.entrySet());
    Collections.sort(list, new Comparator<Entry<String, Integer>>() {
        public int compare(Entry<String, Integer> o1, Entry<String, Integer> o2) {
            if (order) {
                return o1.getKey().compareTo(o2.getKey());
            } else {
                return o2.getKey().compareTo(o1.getKey());

            }
        }
    });
    Map<String, Integer> sortedMap = new LinkedHashMap<String, Integer>();
    for (Entry<String, Integer> entry : list) {
        sortedMap.put(entry.getKey(), entry.getValue());
    }
    printMap(sortedMap);
}

public void printMap(Map<String, Integer> map) {
    // System.out.println(map);
    for (Entry<String, Integer> entry : map.entrySet()) {
        System.out.println(entry.getKey() + " : " + entry.getValue());
    }
}
}

here is the git link

user3123372
  • 704
  • 1
  • 10
  • 26
0

Convert hashmap to a ArrayList with a pair class

Hashmap<Object,Object> items = new HashMap<>();

to

List<Pair<Object,Object>> items = new ArrayList<>();

so you can sort it as you want, or list sorted by adding order.

Amir Hossein Ghasemi
  • 20,623
  • 10
  • 57
  • 53
0

Sorting HashMap by value in Java:

public class HashMapSortByValue {
    public static void main(String[] args) {

        HashMap<Long,String> unsortMap = new HashMap<Long,String>();
            unsortMap.put(5l,"B");
            unsortMap.put(8l,"A");
            unsortMap.put(2l, "D");
            unsortMap.put(7l,"C" );

            System.out.println("Before sorting......");
            System.out.println(unsortMap);

            HashMap<Long,String> sortedMapAsc = sortByComparator(unsortMap);
            System.out.println("After sorting......");
            System.out.println(sortedMapAsc);

    }

    public static HashMap<Long,String> sortByComparator(
            HashMap<Long,String> unsortMap) {

            List<Map.Entry<Long,String>> list = new LinkedList<Map.Entry<Long,String>>(
                unsortMap.entrySet());

            Collections.sort(list, new Comparator<Map.Entry<Long,String>> () {
                public int compare(Map.Entry<Long,String> o1, Map.Entry<Long,String> o2) {
                    return o1.getValue().compareTo(o2.getValue());
                }
            });

            HashMap<Long,String> sortedMap = new LinkedHashMap<Long,String>();
            for (Entry<Long,String> entry : list) {
              sortedMap.put(entry.getKey(), entry.getValue());
            }
            return sortedMap;
          }

}
Eric Aya
  • 69,473
  • 35
  • 181
  • 253
SANTosh Z
  • 1
  • 1