1

I am having an issue with sorting an ArrayList with Ascending order.I am using Comparator and Collator Of Collection class .How can I achieve expected sorting order ? Help is much appreciated.

Ascending order calculated by Algorithm is :

[AutomationRejectNotification|,AutomationRejectNotification1011, AutomationRejectNotification1021,AutomationTestNotification1, AutomationTestNotification100,AutomationTestNotification2,testDisplay Template, Testing Chrome, Testing Field, Test Notfication, testnotif, Test Notification #1]

Expected Ascending Sorting order is:

[AutomationRejectNotification1011, AutomationRejectNotification1021, AutomationRejectNotification|,AutomationTestNotification1, AutomationTestNotification2,AutomationTestNotification100,Test Notfication, Test Notification #1, testDisplay Template, Testing Chrome, Testing Field, testnotif]

Java code:

public static void listSort(List<String> o1, boolean order) {
        final Pattern p = Pattern.compile("^\\d+");
        Comparator<String> c = new Comparator<String>() {
            public int compare(String object1, String object2) {
                Collator collator = Collator.getInstance(Locale.US);
                Matcher m = p.matcher(object1);

                if (!m.find()) {
                    return collator.compare(object1, object2);
                } else {
                    Long number2 = null;
                    Long number1 = Long.parseLong(m.group());

                    m = p.matcher(object2);
                    if (!m.find()) {
                        return collator.compare(object1, object2);
                    } else {

                        number2 = Long.parseLong(m.group());

                        int comparison = number1.compareTo(number2);
                        if (comparison != 0) {
                            return comparison;
                        } else {
                            return collator.compare(object1, object2);
                        }
                    }
                }


            }
        };
        o1.sort(c);
3
  • That's the way Collator works. Take a look at this article: documentation.progress.com/output/Corticon/5.3.2/… Commented Nov 17, 2017 at 14:36
  • No, @WinterN, it is not how Collator works. Note in particular that in the US locale, the | character comes after the decimal digits, so "AutomationRejectNotification|" collates after "AutomationRejectNotification1011", contrary to the ordering reported by the OP. Commented Nov 17, 2017 at 14:40
  • @kaps - rather than providing a single example of your expected output, can you specify the sorting rule that would apply to an arbitrary input list? Commented Nov 17, 2017 at 15:48

1 Answer 1

2

Your Comparator does not properly implement the contract of the Comparator interface, so all bets are off. The compare() method must have all of these properties:

sgn(compare(x, y)) == -sgn(compare(y, x)) for all x and y.

((compare(x, y)>0) && (compare(y, z)>0)) implies compare(x, z)>0.

compare(x, y)==0 implies that sgn(compare(x, z))==sgn(compare(y, z)) for all z.

(API docs)

When both strings being compared contain a non-empty decimal digit sequence, you compare only by the numbers, whereas if at least one string is without any digits then you compare via the collator. That produces these results:

compare("z1", "y") > 0

compare("y", "x3") > 0

compare("z1", "x3") < 0

, which do not conform to the second required property (transitivity).

Possibly what you want to do is is compare the longest leading digitless substrings as a first criterion, breaking any ties by comparing the trailing numbers, if any. That might look like this:

public static void listSort(List<String> o1, boolean order) {
    final Pattern p = Pattern.compile("([^0-9]*)([0-9]+)?");
    final Collator collator = Collator.getInstance(Locale.US);
    Comparator<String> c = new Comparator<String>() {
        public int compare(String object1, String object2) {
            Matcher m1 = p.matcher(object1);
            Matcher m2 = p.matcher(object2);

            if (!m1.lookingAt() || !m2.lookingAt()) {
                assert false : "Should never happen";
            }

            int result = collator.compare(m1.group(1), m2.group(1));

            if (result == 0) {
                String digits1 = m1.group(2);
                String digits2 = m2.group(2);

                if (digits1 != null && digits2 != null) {
                    Long number1 = Long.valueOf(digits1);
                    Long number2 = Long.valueOf(digits2);
                    result = number1.compareTo(number2);
                } else if (digits1 != null) {
                    result = 1;
                } else if (digits2 != null) {
                    result = -1;
                }
            }

            return result;
        }
    };
    o1.sort(c);
}

That would be consistent with the expected order you presented, but there are other ordering schemes that would also produce the same result for those particular elements.

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

3 Comments

Hi @John Bollinger : Thanks for your inputs . It throws below error .java.lang.NumberFormatException: For input string: "Test-AutomationTestNotification" at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65) at java.lang.Long.parseLong(Long.java:589) at java.lang.Long.valueOf(Long.java:803)
I have all special characters in some of the test data. i.e Test Motification #1,Test Motifcaiotn@34
@kaps, I suspect you could have troubleshot that problem yourself, but nevertheless, I have fixed it.

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.