0

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?

2
  • 3
    Why you don't use Map<Integer, String> unsortMap ? Commented Feb 2, 2016 at 7:13
  • Note "9" > "10" as you should expect. If you want to compare them as Integer, use Integer. Commented Feb 2, 2016 at 9:32

3 Answers 3

4

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.

Sign up to request clarification or add additional context in comments.

Comments

2

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.

Comments

0

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());
}

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.