Search code examples
javastringcomparecomparetolexicographic

Sorting String List by rules


How to sort string list apart from ascending or descending order based on ACII table using comparator or comparable.

Let us assume that a string list contains words which starts with either number (1start) or special character (@fill) or lowercase (kind) or uppercase (Link)

Sample scenario: I would like to sort the list in this particular order: (sorting an be either asc or desc)

  • words which starts with 'lowercase' should be sorted first,
  • words which starts with 'special' character should be sorted second,
  • words which starts with 'number' should be sorted third,
  • words which starts with 'uppercase' should be sorted fourth

Solution

  • I'd create an enum for each of these "character classes", with some logic to figure out what class each character belongs to:

    public enum CharacterClass {
        LOWERCASE, SPECIAL, NUMBER, UPPERCASE;
    
        public static CharacterClass getClass(char c) {
            if (Character.isLowerCase(c)) {
                return LOWERCASE;
            }
            if (Character.isUpperCase(c)) {
                return UPPERCASE;
            }
            if (Character.isDigit(c)) {
                return NUMBER;
            }
            return SPECIAL;
        }
    }
    

    Based on that, we can now create a comparator that goes over the characters of two strings and compares their classes (and then the characters themselves, if they have the same class):

    public class CharacterClassComparator implements Comparator<String> {
        @Override
        public int compare(String o1, String o2) {
            int l1 = o1.length();
            int l2 = o2.length();
            int length = Math.min(l1, l2);
    
            for (int i = 0; i < length; ++i) {
                char c1 = o1.charAt(i);
                char c2 = o2.charAt(i);
    
                // Compare the character classes
                int res = CharacterClass.getClass(c1).compareTo(CharacterClass.getClass(c2));
                if (res != 0) {
                    return res;
                }
    
                // If the clases are the same, compare the actual characters
                res = Character.compare(c1, c2);
                if (res != 0) {
                    return res;
                }
            }
    
            // All the characters up to the shared length are the same
            // Compare the lengths:
            return Integer.compare(l1, l2);
        }
    }