5

I have a requirement to sort objects(Zone) with their names(Zone Name : String) considering the case. I tried this with Java Comparator interface.

class NameComparator implements Comparator<Zone> {
    public int compare(Zone z1, Zone z2) {
        return z1.getZoneName().compareTo(z2.getZoneName());
   }
}

But this Comparator only sort lexicographically.

Ex : Required order for the zone names.

['Zone AAa3','Zone aaa3','Zone BBB7','Zone BBb7','Zone bbb7']

Current Output :

['Zone AAa3','Zone BBB7','Zone BBb7','Zone aaa3','Zone bbb7']

Is there any way to achieve this, other than writing a raw object sorting method?

2 Answers 2

10

There is a pre-defined comparator for case-insensitive sorting. You can use it with a Zone by extracting a sort key.

Comparator<Zone> byName = Comparator
    .comparing(Zone::getZoneName, String.CASE_INSENSITIVE_ORDER)
    .thenComparing(Zone::getZoneName);
Sign up to request clarification or add additional context in comments.

6 Comments

This seems only work for Java 8.But looks like a easier way.Thank you.
@shamikaDharmasiri Well, Java 7 ended support (including security) over a year ago, and Java 9 is almost here. Getting current is worth some effort.
But this does not solve the use case of ordering ('Zone AAa3' < 'Zone aaa3') - If input is Zone aaa3, Zone AAa3, then it does not return Zone AAa3, aaa3.
@SubhrajyotiMajumder Updated to handle that case.
Whenever you find yourself writing ::compareTo, you should rethink what you are doing. The presence of a compareTo method suggests the presence of a natural order which allows either, the use of Comparator.naturalOrder() or, in most cases, omitting the comparator entirely, i.e. Comparator<Zone> byName = Comparator.comparing(Zone::getZoneName, String.CASE_INSENSITIVE_ORDER).thenComparing(Zone::getZoneName);. Though in this specific case, you perhaps want to use Comparator.comparing(Zone::getZoneName, Collator.getInstance()) instead…
|
1

Tweak the logic, convert both name to lower case or upper case and then compare.

public int compare(Zone z1, Zone z2){
  if(z1.getZoneName().toLowerCase().equals(z2.getZoneName().toLowerCase()))
      return z1.getZoneName().compareTo(z2.getZoneName());
  else
      return z1.getZoneName().toLowerCase().compareTo(z2.getZoneName().toLowerCase());
}

Using lambda -

Comparator<Zone> byName = (z1, z2)->{
    if(z1.getZoneName().toLowerCase().equals(z2.getZoneName().toLowerCase()))
       return z1.getZoneName().compareTo(z2.getZoneName());
    else
       return z1.getZoneName().toLowerCase().compareTo(z2.getZoneName().toLowerCase());
};

3 Comments

Then the case is not considered.I also need the case to be considered.I cannot assure this order, 'Zone AAa3' < 'Zone aaa3'
updated answer - supported use case 'Zone AAa3' < 'Zone aaa3'
The conversion to lower case is an unnecessary waste of performance and may not cover all cases of Unicode letters. Mind the existence of String.compareToIgnoreCase(String) and String.equalsIgnoreCase(String) which perform exactly the desired operation.

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.