简体   繁体   中英

Sorted HashMap Data using java

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?

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.

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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM