1

So I'm trying to sort a String Array using a Comparator but the sorting is based on the length of String then on the third Character of the String.

This is my Comparator so far:

class StringSorter implements Comparator<String> {
    public int compare(String s1, String s2) {
        if(s1.length() < s2.length()) {
            return -1;
        }
        if(s1.length() > s2.length()) {
            return 1;
        }    
        return s1.charAt(3)+"".compareTo(s2.charAt(3)+"");
    }
}//Comparator

This line return s1.charAt(3)+"".compareTo(s2.charAt(3)+""); is my attempt so far and I get an IndexOutOfBoundsException but every String in my Array has at least the length of 4 so I don't understand why the error.

As for my question, why do I get that error? and is that how I should write my Comparator if I'm to sort based on length and a character in the String?

Edit: The Arrays I need to process follows this format

{"1:bbbbb", "2:aaa", "=:ccc", "1:qqqq", "1:eeee", "=:zzz", "1:vvv", "2:oooo", "=:eee", "1:fffff"}
11
  • you question needs to be verifiable, so please provide sample inputs Commented Sep 1, 2017 at 15:59
  • 1
    "but every String in my Array has at least the length of 4 so I don't understand why the error." It is wrong as otherwise you would not have the exception. Set a breakpoint and run in debug mode or other way : add a check and throw an exception if the String length is superior to 4. Commented Sep 1, 2017 at 15:59
  • 2
    Observation : does compareTo get called on "" or on s1.charAt(3)+""? Interesting order precedence thing here, maybe. Commented Sep 1, 2017 at 16:00
  • 3
    Note that your code could be simplified (and made correct, and made clearer, and made faster) to Comparator<String> c = Comparator.comparingInt(String::length).thenComparingInt(s -> s.charAt(3));. Commented Sep 1, 2017 at 16:02
  • 1
    No need to do all to convert to string etc. Just use- new Character(s1.charAt(2)).compareTo(s2.charAt(2)) Commented Sep 1, 2017 at 17:10

2 Answers 2

2

Your code works fine. I've tweaked it a bit here to show you how you can make it more resilient though.

class StringSorter implements Comparator<String> {
    private final int pos;

    public StringSorter(int pos) {
        this.pos = pos;
    }

    public int compare(String s1, String s2) {
        if (s1.length() < s2.length()) {
            return -1;
        }
        if (s1.length() > s2.length()) {
            return 1;
        }
        if ( s1.length() <= pos ) {
            return s1.compareTo(s2);
        }
        return Character.compare(s1.charAt(pos),s2.charAt(pos));
    }
}

public void test() {
    String[] test2 = {"1:bbbbb", "2:aaa", "=:ccc", "1:qqqq", "1:eeee", "=:zzz", "1:vvv", "2:oooo", "=:eee", "1:fffff"};
    System.out.println("Before: " + Arrays.toString(test2));
    Arrays.sort(test2, new StringSorter (2));
    System.out.println("After:  " + Arrays.toString(test2));
}

prints:

Before: [1:bbbbb, 2:aaa, =:ccc, 1:qqqq, 1:eeee, =:zzz, 1:vvv, 2:oooo, =:eee, 1:fffff]

After: [2:aaa, =:ccc, =:eee, 1:vvv, =:zzz, 1:eeee, 2:oooo, 1:qqqq, 1:bbbbb, 1:fffff]

I suspect you are using 3 meaning the 3rd character - this is wrong. The 3rd character is at position 2;

Remember - the nth character in a String is indexed by [n-1] because the first is at 0.

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

Comments

1

This is solution for your problem using ternary operator.

Simple one liner comparison method.

class StringSorter implements Comparator<String> {

    @Override
    public int compare(String s1, String s2) {
        return s1.length() - s2.length() != 0 ? s1.length() - s2.length() :  new Character(s1.charAt(2)).compareTo(s2.charAt(2));
    }
}

Comments

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.