58

How can I sort a LinkedHashMap<String, Integer> based on its values?.

I need to sort it based on the values which are Integers.

3
  • 2
    Do you have to use a LinkedHashMap? TreeMap might help? Commented Aug 29, 2012 at 18:37
  • 2
    this may help stackoverflow.com/questions/780541/how-to-sort-hash-map Commented Aug 29, 2012 at 18:37
  • Oh. I see. Didn't bother to read the comments. ^_^ Commented Aug 29, 2012 at 18:39

5 Answers 5

81
List<Map.Entry<String, Integer>> entries =
  new ArrayList<Map.Entry<String, Integer>>(map.entrySet());
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());
  }
});
Map<String, Integer> sortedMap = new LinkedHashMap<String, Integer>();
for (Map.Entry<String, Integer> entry : entries) {
  sortedMap.put(entry.getKey(), entry.getValue());
}
Sign up to request clarification or add additional context in comments.

5 Comments

Well dammit, I was writing the exact same code! :) Except for the last part, I don't think OP actually needs to have them back in a map.
Nice answer. I had to sort in descending order so, added a -ve sign while returning value from the Comparator.
Prefer to switch the order of the arguments; negation doesnt always work if the original compareTo returned Integer.MIN_VALUE.
That is, write b.getValue().compareTo(a.getValue()).
You don't need to change the comparator. You can use Collections.reverseOrder(comparator) which makes the meaning more obvious.
51

This is now quite a bit easier with Java 8 streams: you don't need the intermediate map to sort:

map.entrySet().stream()
    .sorted(Map.Entry.comparingByValue())
    .forEach(entry -> ... );

7 Comments

What's in those three dots?
Those three dots represent whatever you want to do with the sorted values. It might be to call another method, print them, collect them in a different map - whatever your problem requires.
Why is this answer accepted and so highly ratet? It does not answer how to sort the map itself. It just tells how to process the contents of the map in a specific order.
@Guardian667 Maps themselves cannot be sorted in place. That's quite clear in the documentation for the interface though some maps make guarantees of their order. I suspect OP and upvoters realised that and understood 'sorting the map based on its values' to mean using the entries in order of their values. No other interpretation of the question makes any sense.
A LinkedHashMap (the type of map mentioned in the comment) absolutely could be sorted in place — stackoverflow.com/a/79694728/1108305, so such an interpretation is sensible. That said, "using the entries in order of their values" is probably the more appropriate solution in most cases.
I'm not sure I agree with your definition of 'in place' - creating a new data structure (a list of map entries) isn't really in the same 'place' as the original map. But semantics aside I agree that either a new structure or a stream of the map could be placed in any required order.
Yeah, I guess there's an argument to be made that needing a full copy's worth of data in order to then reorder the original map may not meet the needs of "in place" sorting, if that needed to be avoided. I was thinking more along the lines that they wanted the original map reordered, which that solution does do (albeit at the cost of first creating a copy of the entire data). A O(n^2) sort that would be in place that I can think of would be to iterate over the map, find the smallest element, and then call putLast with it. Then continue to repeat this for the unsorted portion.
3

LinkedHashMap just maintains insertion order. If you want to sort based on value, you may need to write your own comparator.

6 Comments

I don't think you need to write your own comparator. Map.Entry.comparingByValue() should generate one for you. And it can be reversed by Collections.reverseOrder(Map.Entry.comparingByValue()).
@sprinter: What if the value is type of any custom object?
@Nambari Either have that type implement Comparable or provide a customer Comparator to Map.Entry.comparingByValue.
@sprinter: Exactly, that is what this answer was about.
and how would you use that comparator? are you providing a different solutions from the others
|
1
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.NavigableMap;
import java.util.SortedMap;
import java.util.TreeMap;

public class HashMapTest {

public static void main(String[] args) {

    Map<String, Integer> map=new LinkedHashMap<String, Integer>();

    map.put("a", 11);
    map.put("B", 12);
    map.put("c", 3);
    map.put("d", 4);
    map.put("e", 5);
    map.put("f", 6);
    map.put("g", 7);
    map.put("h", 8);
    map.put("i", 9);
    map.put("j", 3);
    map.put("k", 2);
    map.put("l", 1);

    List<Map.Entry<String, Integer>> entries = new 
    ArrayList<Map.Entry<String, Integer>>(map.entrySet());
            Collections.sort(entries,new CustomizedHashMap());


            Map<String, Integer> sortedMap = new LinkedHashMap<String, 
   Integer>();
            for (Map.Entry<String, Integer> entry : entries) {
              sortedMap.put(entry.getKey(), entry.getValue());
              System.out.print( sortedMap.put(entry.getKey(), 
          entry.getValue())+"  ");
            }
     }
    }

 class CustomizedHashMap implements Comparator<Map.Entry<String, Integer>> {

  @Override
  public int compare(Entry<String, Integer> o1, Entry<String, Integer> o2) {
    // TODO Auto-generated method stub
    return -o1.getValue().compareTo(o2.getValue());
  }

}

1 Comment

new CustomizedHashMap() can be replaced by Map.Entry.comparingByValue().reversed(). Also, CustomizedHashMap sounds like it would be a Map implementation, not a Comparator implementation. Those specifics aside, this is definitely a sensible approach.
1

It is possible to sort the LinkedHashMap in place (as a strict reading of your question suggests you are asking for).

First create a sorted copy of the data, then reorder the original map by calling its putLast method with each sorted element. The result of this will be the original map in the desired sorted order.

LinkedHashMap<String, Integer> map = getMyLinkedHashMap();

List<Map.Entry<String, Integer>> sortedEntries = map.entrySet().stream()
        .map(Map.Entry::copyOf) // Use AbstractMap.SimpleImmutableEntry instead if key or value may be null
        .sorted(Map.Entry.comparingByValue())
        .toList();

sortedEntries.forEach(e -> map.putLast(e.getKey(), e.getValue()));

Example:

LinkedHashMap<String, Integer> map = new LinkedHashMap<>();
map.put("A", 1);
map.put("B", 2);
map.put("C", 1);
map.put("D", 4);
map.put("E", 0);

List<Map.Entry<String, Integer>> sortedEntries = map.entrySet().stream()
        .map(Map.Entry::copyOf)
        .sorted(Map.Entry.comparingByValue())
        .toList();

sortedEntries.forEach(e -> map.putLast(e.getKey(), e.getValue()));


System.out.println(map); // {E=0, A=1, C=1, B=2, D=4}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.