Search code examples
javasortingarraylistcollectionsjava-8

Java List String sort Based on Integer with multiple underscore's


Hi All I have arrayList of String datatype but needs to sort like integer with multiple underscore's using Java 8 only ,For your reference I have added sample data, the original data came Liferay 7.1 DDL

List<String> keyValues = new ArrayList<String>();
keyValues.add("100_10_20_1");
keyValues.add("100001");
keyValues.add("100002");
keyValues.add("100002_1");
keyValues.add("100003");
keyValues.add("100");
keyValues.add("100_1");
keyValues.add("100_2");
keyValues.add("100_1_1");
keyValues.add("100_10_20");
keyValues.add("10000001");
keyValues.add("100_10_20_2");

i tried to replace the underscore with 0 but what happens sometimes 100_1 replace _ with 0 then it becomes 10001 but what if i already have 10001 value present in list ? even same thing for empty if i replace _ with "" then it becomes 1001 but what if i already have 1001 then again i am facing issue

Exact logic based on underscore was

 100
 100_1
 100_1_2 
 /after that only/
 100_2
 100_2_2
/after that/
 103
 104
 105
 10000
/similarly the pattern repeats/
 10000_1
 10000_2
 10000_2_1
 100002

i need the exact output as

    100
    100_1
    100_1_1
    100_2
    100_10_20
    100_10_20_1
    100_10_20_2
    100001
    100002
    100002_1
    100003
    10000001

i tried with replacing underscore with 0 or empty space but there is possiblity of if it had already that number present in list,if i replace with dot and storing as Double then multiple pointer exception will occur


Solution

  • I made a comparator then split the string and process based on the min amount of tokens each string has.

    static Comparator<String> stringComparator = new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                String[] s1 = o1.split("_");
                String[] s2 = o2.split("_");
    
                int minLen = Math.min(s1.length, s2.length);
    
                for (int i=0; i < minLen; i++){
                    if (!s1[i].equals(s2[i])){
                        return Integer.parseInt(s1[i]) - Integer.parseInt(s2[i]);
    //                    return s1[i].compareTo(s2[i]);  //not natural order/sort
                    }
                }
    
                return o1.compareTo(o2);
            }
        };
    

    Calling it like so:

        List<String> keyValues = new ArrayList<String>();
        keyValues.add("100001");
        keyValues.add("100002");
        keyValues.add("100002_1");
        keyValues.add("100003");
        keyValues.add("100");
        keyValues.add("100_1");
        keyValues.add("100_2");
        keyValues.add("100_1_1");
        keyValues.add("100_10_20");
        keyValues.add("10000001");
        keyValues.stream().sorted(stringComparator).forEach(System.out::println);
    

    Gives output:

    100
    100_1
    100_1_1
    100_2
    100_10_20
    100001
    100002
    100002_1
    100003
    10000001