@Note: This is categorized as “Difficult” because it is a common trick question. Many freshers try to sort a HashMap in-place or use a TreeMap incorrectly, failing to understand how memory models define collection interfaces.
Category: Difficult | Concepts used: Custom comparators, Java Streams, LinkedHashMap for ordered results
Problem Statement
Given a HashMap<String, Integer>, sort its entries by value (not key), and produce an ordered result.
Input : {apple=50, banana=20, cherry=80} Output (ascending by value): {banana=20, apple=50, cherry=80}
Note: Important context:
HashMapitself has no inherent order — you can’t literally “sort a HashMap in place.” What we actually produce is an ordered representation (typically aLinkedHashMap, or aListof entries) that reflects the sorted order.
Examples (with edge scenarios)
| # | Input | Sort Order | Output | Why |
|---|---|---|---|---|
| 1 | {apple=50, banana=20, cherry=80} | Ascending | {banana=20, apple=50, cherry=80} | Smallest value first |
| 2 | {apple=50, banana=20, cherry=80} | Descending | {cherry=80, apple=50, banana=20} | Largest value first |
| 3 | {} (empty map) | Either | {} | Nothing to sort |
| 4 | {a=1} (single entry) | Either | {a=1} | Trivially “sorted” |
| 5 | {a=5, b=5, c=3} (tie values) | Ascending | {c=3, a=5, b=5} (tie-break order may vary) | When values tie, secondary ordering (e.g., by key) may need clarifying |
Common Fresher Mistake
Mistake What happens Fix Trying to “sort the HashMap in place” Not possible — HashMapprovides no ordering guarantee by designConvert to a sortable structure (list of entries, or LinkedHashMapfor the final ordered output)Using a TreeMapdirectly for this (assuming it sorts by value)TreeMapsorts by key, not value, by default — using it here would be a mismatchTreeMapis for sorting by KEY; for sorting by VALUE, convert entries to a list and sort with a custom comparator, or use Java Streams
Before You Code: Clarify the Contract
Before choosing an algorithm, confirm whether equal values need a secondary key order, whether the original map must remain unchanged, and whether null keys or values are permitted. A HashMap does not preserve display order, so the sorted result needs an order-preserving map or list.
Analogy: Sorting Mailboxes by Letters Count
Imagine you are a postmaster managing a wall of locked mailboxes (a HashMap):
- The mailboxes are labeled with resident names (keys), and inside each is a stack of letters (values):
{apple=50 letters, banana=20 letters, cherry=80 letters}. - You cannot physically rearrange the built-in mailboxes in the wall (HashMap has no inherent order).
- To present them sorted by letter count:
- Step 1 (Extraction): You write down every mailbox’s name and letter count on individual index cards (
List<Map.Entry>). - Step 2 (Sorting): You line up the index cards on a table and sort them from smallest letter count to largest:
[banana=20, apple=50, cherry=80]. - Step 3 (Rebuilding): You take a new rolling catalog cart (
LinkedHashMap) and place the index cards into it, one-by-one, in that sorted order. - When someone scrolls through the catalog cart, they see the mailboxes listed in the perfect sorted order!
- Step 1 (Extraction): You write down every mailbox’s name and letter count on individual index cards (
Solution 1 — Convert to a List of Entries, Sort with a Comparator (Classic Approach)
Intuition
Since a HashMap itself can’t be reordered, the standard trick is: pull all its entries out into a List<Map.Entry<K,V>> (a list CAN be sorted), sort that list using a comparator that compares by value, and then (if a map-like structure is still wanted) rebuild a LinkedHashMap by inserting the entries in that newly sorted order — LinkedHashMap remembers insertion order, so it “looks sorted” when iterated.
import java.util.*;
public class SortHashMapByValueClassic {
public static LinkedHashMap<String, Integer> sortByValue(HashMap<String, Integer> map) {
// Step 1: pull entries into a sortable list
List<Map.Entry<String, Integer>> entryList = new ArrayList<>(map.entrySet());
// Step 2: sort the list by value, ascending
entryList.sort((e1, e2) -> e1.getValue().compareTo(e2.getValue()));
// Step 3: rebuild an ordered map from the sorted list
LinkedHashMap<String, Integer> sortedMap = new LinkedHashMap<>();
for (Map.Entry<String, Integer> entry : entryList) {
sortedMap.put(entry.getKey(), entry.getValue());
}
return sortedMap;
}
public static void main(String[] args) {
HashMap<String, Integer> map = new HashMap<>();
map.put("apple", 50);
map.put("banana", 20);
map.put("cherry", 80);
System.out.println(sortByValue(map)); // {banana=20, apple=50, cherry=80}
}
}
Output:
{banana=20, apple=50, cherry=80}
Dry Run (map = {apple=50, banana=20, cherry=80})
Step 1: entryList = [apple=50, banana=20, cherry=80] (order from HashMap, not guaranteed)
Step 2: sort by value ascending:
Compare 50 vs 20 -> 20 comes first
Compare 50 vs 80 -> 50 comes first
Sorted: [banana=20, apple=50, cherry=80]
Step 3: rebuild LinkedHashMap by inserting in this order:
put(banana,20) -> {banana=20}
put(apple,50) -> {banana=20, apple=50}
put(cherry,80) -> {banana=20, apple=50, cherry=80}
Final: {banana=20, apple=50, cherry=80}
Interviewer’s take
This is the classic, foundational solution that demonstrates real understanding — extracting entries, sorting with a comparator, and rebuilding a LinkedHashMap shows you understand exactly why HashMaps can’t be sorted directly and how to work around that limitation properly. Interviewers specifically want to hear you explain why LinkedHashMap (not another HashMap) is used for the final result — it’s the only standard Map implementation that preserves insertion order.
Follow-up questions you might get:
- “Why can’t you just sort a
HashMapdirectly?” →HashMaporganizes entries internally by hash code for fast lookup — it has no concept of “position” or “order” to sort in the first place. - “Why use
LinkedHashMapfor the result instead of a regularHashMap?” →LinkedHashMapmaintains a separate linked list tracking insertion order — inserting in sorted order means iterating it later will reflect that sorted order; a regularHashMapwould immediately lose that ordering. - “How would you sort descending instead?” → Reverse the comparator:
(e1, e2) -> e2.getValue().compareTo(e1.getValue()).
Solution 2 — Using Java Streams (Concise, Modern)
Intuition
Same fundamental plan as Solution 1 (extract entries, sort, rebuild), but expressed declaratively using the Streams API — “take this map’s entry stream, sort it by value, then collect it back into an ordered map.”
import java.util.*;
import java.util.stream.*;
public class SortHashMapByValueStreams {
public static LinkedHashMap<String, Integer> sortByValue(HashMap<String, Integer> map) {
return map.entrySet()
.stream()
.sorted(Map.Entry.comparingByValue()) // ascending by value
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(e1, e2) -> e1, // merge function (unused here, but required)
LinkedHashMap::new // preserve sorted order in the result
));
}
public static void main(String[] args) {
HashMap<String, Integer> map = new HashMap<>();
map.put("apple", 50);
map.put("banana", 20);
map.put("cherry", 80);
System.out.println(sortByValue(map)); // {banana=20, apple=50, cherry=80}
}
}
Output:
{banana=20, apple=50, cherry=80}
Interviewer’s take
A nice, modern one-liner-style solution — completely acceptable and shows familiarity with Streams. Map.Entry.comparingByValue() is a handy built-in comparator specifically for this exact use case. The one tricky part to explain if asked: the Collectors.toMap() call needs a merge function (third argument) as a technical requirement to resolve key collisions, even though duplicate keys can’t practically occur when sorting an existing map’s own entries — and the fourth argument (LinkedHashMap::new) is what ensures the result actually preserves the sorted order (using the default would silently produce an unordered HashMap, undoing all the sorting work!).
Follow-up questions you might get:
- “Why does
Collectors.toMap()need a merge function here?” → It’s a required parameter of that particular overload to resolve what happens if two entries end up with the same key during collection — even though that can’t practically happen here, Java’s API still requires it to be provided when you also want to specify the map factory (LinkedHashMap::new). - “What happens if you forget the
LinkedHashMap::newargument?” → The defaultCollectors.toMap()(without a specified factory) produces a regularHashMap, which would immediately lose the sorted order — a subtle bug that’s easy to introduce if this detail is missed.
📊 Visual Flowchart
graph TD
Start["Unordered HashMap"] --> Step1["1. Extract to List of Entry objects<br>List<Map.Entry<K,V>>"]
Step1 --> Step2["2. Sort Entry list using Custom Comparator<br>(e1, e2) -> e1.value.compareTo(e2.value)"]
Step2 --> Step3["3. Rebuild into LinkedHashMap<br>(Preserves insertion order)"]
Step3 --> End["Ordered LinkedHashMap"]
Final Verdict — Which Solution Should You Give?
- Both solutions are excellent. Solution 1 (classic list + comparator + rebuild) is great for demonstrating fundamental understanding — especially valuable for QA/fresher interviews where explaining the “why” matters. Solution 2 (Streams) is a nice, concise, modern alternative to mention afterward.
- The single most important concept to communicate clearly:
HashMaphas no inherent order — “sorting” it means producing a new, order-preserving structure, not modifying the original map’s internal ordering (which doesn’t exist).
Quick Recap
| Approach | Time | Space | Interview Signal |
|---|---|---|---|
List + Comparator + rebuild LinkedHashMap | O(n log n) | O(n) | Shows fundamental understanding |
Streams (sorted + Collectors.toMap) | O(n log n) | O(n) | Concise, modern — watch the merge-function/factory details |
- Author
- TechByteByByte Editorial Team
- Reviewed by
- TechByteByByte Admin
- Published
- Last reviewed