Java
HashMap
Sorting
Data Structures
Programming

Sorting HashMap by values

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Introduction

A HashMap in Java is not sorted, and sometimes you need to order its entries by value instead of by key. The complication appears when multiple keys share the same value. If you choose the wrong data structure, duplicate values can cause entries to disappear.

The safe approach is to sort the map’s entry set and collect the result into an insertion-ordered map such as LinkedHashMap. That preserves all entries, including those with equal values.

Why Duplicate Values Cause Trouble

A common mistake is to move entries into a TreeMap keyed by value. That seems attractive because TreeMap is sorted, but it can only hold one entry for each key. If two original map entries share the same value, one overwrites the other.

For example, this loses data conceptually:

java
Map<String, Integer> scores = new HashMap<>();
scores.put("alice", 90);
scores.put("bob", 90);

If you try to use the score as a unique key in a second map, one of those names disappears because both entries compete for the same value key.

Sort the Entries Instead

The correct pattern is to sort the entrySet() and keep the key-value pairs intact.

In modern Java, streams make this straightforward:

java
1import java.util.Comparator;
2import java.util.HashMap;
3import java.util.LinkedHashMap;
4import java.util.Map;
5import java.util.stream.Collectors;
6
7public class SortByValueExample {
8    public static void main(String[] args) {
9        Map<String, Integer> scores = new HashMap<>();
10        scores.put("alice", 90);
11        scores.put("bob", 90);
12        scores.put("carol", 75);
13        scores.put("dave", 95);
14
15        Map<String, Integer> sorted = scores.entrySet()
16            .stream()
17            .sorted(
18                Map.Entry.<String, Integer>comparingByValue()
19                    .thenComparing(Map.Entry.comparingByKey())
20            )
21            .collect(Collectors.toMap(
22                Map.Entry::getKey,
23                Map.Entry::getValue,
24                (left, right) -> left,
25                LinkedHashMap::new
26            ));
27
28        System.out.println(sorted);
29    }
30}

This preserves duplicate values because the comparator sorts entries, not unique value keys. The LinkedHashMap keeps the sorted insertion order after collection.

Why the Tie-Breaker Matters

When two entries have the same value, the primary comparator sees them as equal. Adding thenComparing(Map.Entry.comparingByKey()) gives the sort a deterministic tie-breaker.

That is useful for two reasons:

  • the output order becomes stable and predictable
  • no custom sorted set treats equal values as duplicate entries to drop

If you only care about value ordering and do not care which equal-value key comes first, the tie-breaker is optional for a list sort. It is still a good habit when deterministic output matters.

Pre-Java 8 Approach

If you are not using streams, sort a List of entries and then rebuild a LinkedHashMap.

java
1import java.util.ArrayList;
2import java.util.HashMap;
3import java.util.LinkedHashMap;
4import java.util.List;
5import java.util.Map;
6
7Map<String, Integer> scores = new HashMap<>();
8scores.put("alice", 90);
9scores.put("bob", 90);
10scores.put("carol", 75);
11
12List<Map.Entry<String, Integer>> entries = new ArrayList<>(scores.entrySet());
13entries.sort(
14    Map.Entry.<String, Integer>comparingByValue()
15        .thenComparing(Map.Entry.comparingByKey())
16);
17
18Map<String, Integer> sorted = new LinkedHashMap<>();
19for (Map.Entry<String, Integer> entry : entries) {
20    sorted.put(entry.getKey(), entry.getValue());
21}

The principle is the same: sort entries, then preserve that order in a map designed to remember insertion order.

Ascending Versus Descending Order

To sort highest values first, reverse the comparator:

java
1Comparator<Map.Entry<String, Integer>> byValueDesc =
2    Map.Entry.<String, Integer>comparingByValue()
3        .reversed()
4        .thenComparing(Map.Entry.comparingByKey());

Be careful with the placement of reversed(). It applies to the comparator built up to that point.

Common Pitfalls

The biggest pitfall is using a map keyed by value and expecting duplicates to survive. Equal values are not unique keys.

Another issue is assuming a sorted stream automatically creates a sorted HashMap. It does not. If you collect back into a plain HashMap, the visible iteration order is no longer guaranteed.

It is also easy to forget a tie-breaker and then wonder why equal values appear in an unstable order between runs or JDK versions.

Finally, remember that sorting produces a snapshot. If the original HashMap changes afterward, the sorted LinkedHashMap does not update automatically.

Summary

  • Do not sort a HashMap by moving values into a second map keyed by value when duplicates are possible.
  • Sort the original entrySet() instead, because entries preserve both key and value together.
  • Collect the result into a LinkedHashMap so iteration order matches the sorted order.
  • Add a tie-breaker such as key comparison for stable output when values are equal.
  • Duplicate values are only a problem when your chosen structure treats the value as a unique key.

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.