Search code examples
javatreemap

How to sort TreeMap based on keys where keys are alpha numeric , but we need to sort based on available numbers only?


I have a TreeMap which needs to be sorted based on keys. Which is default property of TreeMap. But in my case I am not able to figure out the Comparator. Following is my Code.

 public class Test {

    public static void main(String[] args) {

        Map<String, String> aMap = new TreeMap<String, String>(new MyComp());
        aMap.put("02_file.cql", "test");
        aMap.put("01.cql", "test");
        aMap.put("04.cql", "test");
        aMap.put("3_file.cql", "test");
        aMap.put("11_file.cql", "test");
        aMap.put("10_file.cql", "test");
        aMap.put("0_file.cql", "test");
        aMap.put("100_file.cql", "test");
        Set<Map.Entry<String,String>> set = aMap.entrySet();
        for(Map.Entry<String,String> e : set){
            System.out.println(e.getKey() + ":" + e.getValue());
        }

    }
}

class MyComp implements Comparator<String> {

    @Override
    public int compare(String str1, String str2) {
        return str1.compareTo(str2);
    }
}

The output is coming as :

01.cql:test
02_file.cql:test
04.cql:test
0_file.cql:test
100_file.cql:test
10_file.cql:test
11_file.cql:test
3_file.cql:test

Which is not my expected result. I am expecting result like:

0_file.cql:test
01.cql:test
02_file.cql:test
3_file.cql:test
04.cql:test
10_file.cql:test
11_file.cql:test
100_file.cql:test

Which is same as like what NameFileComparator.NAME_COMPARATOR

org.apache.commons.io.comparator.NameFileComparator;

Any suggestion?


Solution

  • The Comparator passed to the TreeMap constructor makes in a some way which compareTo() of String does : a lexicographical comparison.

    But you don't want a lexicographical comparison.
    In your expected, you want only a numeric comparison.
    To achieve it, remove the no digit part of Strings, create two ints from that and compare the ints with Integer.compare(int, int).

    class MyComp implements Comparator<String> {
    
      @Override
      public int compare(String str1, String str2) {
         String notDigit = "[^\\d]";
         int int1 = Integer.parseInt(str1.replaceAll(notDigit, ""));
         int int2 = Integer.parseInt(str2.replaceAll(notDigit, ""));
         return Integer.compare(int1, int2);
      }
    }
    

    Output by using this Comparator:

    0_file.cql:test

    01.cql:test

    02_file.cql:test

    3_file.cql:test

    04.cql:test

    10_file.cql:test

    11_file.cql:test

    100_file.cql:test