Question

A PHP script outputs a list of e-mail addresses in descending order like following:

_abc_@testmail.com
_abc45_@testmail.com
_abc2_@testmail.com
ypaux2aux@yahoo.com
yaremchuk56@testmail.com
vasillevn@hotmail.com
ugur@hotmail.com
twes@gmail.com
tukaux@yahoo.com
ttsetaux1@yahoo.com
tra@testmail.com

In Java, I'm creating an ArrayList from these e-mails, then sorting in descending order. The result is different:

ypaux2aux@yahoo.com
yaremchuk56@testmail.com
vasillevn@hotmail.com
ugur@hotmail.com
twes@gmail.com
tukaux@yahoo.com
ttsetaux1@yahoo.com
tra@testmail.com
_abc45_@testmail.com
_abc2_@testmail.com
_abc_@testmail.com

The difference is caused by the underscore "_". I want to achieve the same sort order as the PHP script. How can I do this? I've no access to the PHP code.

The Java test code I used is:

import java.util.ArrayList;
import java.util.Collections;

public class sorty {

    public static void main(String[] args) {
        ArrayList<String> listStrings = new ArrayList<>();

        listStrings.add("_abc_@testmail.com");
        listStrings.add("_abc45_@testmail.com");
        listStrings.add("_abc2_@testmail.com");
        listStrings.add("ypaux2aux@yahoo.com");
        listStrings.add("yaremchuk56@testmail.com");
        listStrings.add("vasillevn@hotmail.com");
        listStrings.add("ugur@hotmail.com");
        listStrings.add("twes@gmail.com");
        listStrings.add("tukaux@yahoo.com");
        listStrings.add("ttsetaux1@yahoo.com");
        listStrings.add("tra@testmail.com");

        for (int i = 0; i < listStrings.size(); i++) {

            System.out.println(listStrings.get(i));

        }

        Collections.sort(listStrings);
        Collections.reverse(listStrings);

        for (int i = 0; i < listStrings.size(); i++) {

            System.out.println(listStrings.get(i));

        }
        ;

    }

}
Was it helpful?

Solution

I would use an appropriate Collator. Implementing your own comparator isn't the most trivial thing. The nicest would be if you where happy with one of the defaults. e.g.

Collections.sort(listStrings, Collator.getInstance(Locale.US));

Or similar.

If none of the existing ones works for you then using a rule based collator would make your intent clearer then implementing a comparator imo:

String rules = "< a < b < c < '_'" //etc
Collections.sort(listStrings, new RuleBasedCollator(rules));

OTHER TIPS

Sort using a custom comparator that understands underscores are special:

Collections.sort(listStrings, new Comparator<String>() {

    @Override
    public int compare(String o1, String o2) {
        if (o1.startsWith("_") && o2.startsWith("_")) {
            return compare(o1.substring(1), o2.substring(1));
        }

        if (o1.startsWith("_")) {
            return 1;
        }
        if (o2.startsWith("_")) {
            return -1;
        }

        return o1.compareTo(o2);
    }
});

This will also handle the situation where multiple underscores are present. E.g. __foo will be considered after _foo.


To cope with arbitrary numbers of special characters, define them in an array (in your preferred order) and use a more advanced comparator:

Collections.sort(listStrings, new Comparator<String>() {

    // declare in order of desired sort
    private final String[] specialChars = { "_", ">" };

    @Override
    public int compare(String o1, String o2) {
        /*
         * CASES
         * 
         * 1. Both start with same special char
         * 
         * 2. Both start with a special char
         * 
         * 3. One starts with a special char
         * 
         * 4. None starts with a special char
         */

        int o1SpecialIndex = -1;
        int o2SpecialIndex = -1;

        for (int i = 0; i < specialChars.length; i++) {
            if (o1.startsWith(specialChars[i])) {
                o1SpecialIndex = i;
            }
            if (o2.startsWith(specialChars[i])) {
                o2SpecialIndex = i;
            }
        }

        // case 1:
        if (o1SpecialIndex != -1 && o1SpecialIndex == o2SpecialIndex) {
            return compare(o1.substring(1), o2.substring(1));
        }

        // case 2:
        if (o1SpecialIndex != -1 && o2SpecialIndex != -1) {
            return o2SpecialIndex - o1SpecialIndex;
        }

        // case 3:
        if (o1SpecialIndex != -1) {
            return 1;
        }
        if (o2SpecialIndex != -1) {
            return -1;
        }

        // case 4:
        return o1.compareTo(o2);
    }
});
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top