Reputation: 4408
I am trying to sorting HashMap data in acending order by using below code :
public static void main(String[] args) {
Map<String, String> unsortMap = new HashMap<String, String>();
unsortMap.put("10", "z");
unsortMap.put("5", "b");
unsortMap.put("6", "a");
unsortMap.put("20", "c");
unsortMap.put("1", "d");
unsortMap.put("7", "e");
unsortMap.put("8", "y");
unsortMap.put("99", "n");
unsortMap.put("50", "j");
unsortMap.put("2", "m");
unsortMap.put("9", "f");
System.out.println("Unsort Map......");
printMap(unsortMap);
System.out.println("\nSorted Map......");
Map<String, String> treeMap = new TreeMap<String, String>(unsortMap);
printMap(treeMap);
}
public static void printMap(Map<String, String> map) {
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println("Key : " + entry.getKey()
+ " Value : " + entry.getValue());
}
}
Output of this program :
Sorted Map......
Key : 1 Value : d
Key : 10 Value : z
Key : 2 Value : m
Key : 20 Value : c
Key : 5 Value : b
Key : 50 Value : j
Key : 6 Value : a
Key : 7 Value : e
Key : 8 Value : y
Key : 9 Value : f
Key : 99 Value : n
Expected Output :
Sorted Map......
Key : 1 Value : d
Key : 2 Value : m
Key : 5 Value : b
Key : 6 Value : a
Key : 7 Value : e
Key : 8 Value : y
Key : 9 Value : f
Key : 10 Value : z
Key : 20 Value : c
Key : 50 Value : j
Key : 99 Value : n
I know If I used character instead on number (for example 1 as 'A', 2 as 'C', .. 99 as 'E') then above code print the correct result. But why its not working when I used integer as string type in key?
Upvotes: 0
Views: 90
Reputation: 86764
The key type is String
, so the values are stored and compared as strings lexicographically. Individual strings are compared left to right, not as numeric values. The output you got is the correct output for sorting strings.
If you want the values compared as integers, either define your generic parameters as <Integer,String>
or implement a new comparator for the TreeMap
that converts the strings to integer for comparison.
Here's a sample comparator
public static class StringAsNumberComparator implements Comparator<String>
{
public static class StringAsNumberComparator implements Comparator<String>
{
@Override
public int compare(String o1, String o2)
{
/*
* A string compares equal to itself, and two null values are also equal.
* Note that we *really DO* want to use reference comparison here instead of String.equals().
* This is an optimization to detect a string being compared to itself (not another string
* that happens to contain the same value).
*/
if (o1 == o2) return 0; // A string compares equal to itself
/*
* Also we DO NOT do this:
*
* if (o1 != null && o2 != null && o1.equals(o2)) return 0;
*
* with the goal of detecting equal-valued because we want all strings to go
* through the conversion below, where null and invalid numbers are detected
* and mapped to Integer.MIN_VALUE so they'll sort to the front.
*/
int temp1, temp2;
/*
* Convert the first string into a number for comparison.
* If the first string is null or not a valid number make it sort to the beginning
*/
try {
temp1 = o1==null ? Integer.MIN_VALUE : Integer.parseInt(o1);
} catch (NumberFormatException nx) {
temp1 = Integer.MIN_VALUE;
}
/*
* Convert the second string into a number for comparison.
* If the second string is null or not a valid number make it sort to the beginning
*/
try {
temp2 = o2==null ? Integer.MIN_VALUE : Integer.parseInt(o2);
} catch (NumberFormatException nx) {
temp2 = Integer.MIN_VALUE;
}
/*
* Do the actual comparison
*/
return Integer.compare(temp1, temp2);
}
}
You would need to modify your code as follows
System.out.println("\nSorted Map......");
Map<String, String> treeMap = new TreeMap<>(new StringAsNumberComparator()); // <=== different constructor to set Comparator
treeMap.putAll(unsortMap); // <=== Here's where you copy the elements in
printMap(treeMap);
One possible enhancement would be to parameterize the comparator so you could give it the value to use for invalid or null strings to make them sort to the beginning (Integer.MIN_VALUE
) or the end (Integer.MAX_VALUE
). I'll leave that as an exercise.
Upvotes: 4
Reputation: 1289
use this code
Map<Integer, String> map = new TreeMap<Integer, String>(unsortMap);
System.out.println("After Sorting:");
Set set2 = map.entrySet();
Iterator iterator2 = set2.iterator();
while(iterator2.hasNext()) {
Map.Entry me2 = (Map.Entry)iterator2.next();
System.out.print(me2.getKey() + ": ");
System.out.println(me2.getValue());
}
Upvotes: 0
Reputation: 198324
It is working, just not the way you want it. Strings are compared lexicographically, not numerically. Look at the dictionary: would the order be "A", "Aardvark", "B" - or would it be "A", "B", "Aardvark"? Same here: 1
and 10
both start with 1
, so they are together; and since 1
is a prefix of 10
, 1
comes before.
Upvotes: 2