48

I need to sort list of strings in the alphabetical order:

List<String> list = new ArrayList();
list.add("development");
list.add("Development");
list.add("aa");
list.add("AA");
list.add("Aa");

A common way to do it is to use comparator:

Collections.sort(list, String.CASE_INSENSITIVE_ORDER);

The problem of the CaseInsensitiveComparator that “AA” is equals to “aa”. Strings appear in the result according to the order of adding for the same values, and it is not correct:

"aa","AA","Aa","development","Development"
Raedwald
  • 46,613
  • 43
  • 151
  • 237
Michael
  • 10,063
  • 18
  • 65
  • 104
  • 5
    When you write that treating "AA" and "aa" the same “is not correct”, then what is your exact definition of “alphabetical order”? Your top-voted but yet un[accept](http://meta.stackexchange.com/q/5234/188688)ed answer suggests that you want to break ties by using the “normal” case-sensitive comparison. To give you an idea of how complex “alphabetical sorting” is in the unicode world and with different locales, have a look at what the [ICU](http://site.icu-project.org/) User Guide writes about [collation](http://userguide.icu-project.org/collation). – MvG Sep 13 '12 at 19:18

4 Answers4

80

If you don't want to add a dependency on Guava (per Michael's answer) then this comparator is equivalent:

private static Comparator<String> ALPHABETICAL_ORDER = new Comparator<String>() {
    public int compare(String str1, String str2) {
        int res = String.CASE_INSENSITIVE_ORDER.compare(str1, str2);
        if (res == 0) {
            res = str1.compareTo(str2);
        }
        return res;
    }
};

Collections.sort(list, ALPHABETICAL_ORDER);

And I think it is just as easy to understand and code ...

The last 4 lines of the method can written more concisely as follows:

        return (res != 0) ? res : str1.compareTo(str2);
Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
16

The simple way to solve the problem is to use ComparisonChain from Guava http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/ComparisonChain.html

private static Comparator<String> stringAlphabeticalComparator = new Comparator<String>() {
        public int compare(String str1, String str2) {
            return ComparisonChain.start().
                                compare(str1,str2, String.CASE_INSENSITIVE_ORDER).
                                compare(str1,str2).
                                result();
         }
 };
Collections.sort(list, stringAlphabeticalComparator);

The first comparator from the chain will sort strings according to the case insensitive order, and the second comparator will sort strings according to the case insensitive order. As excepted strings appear in the result according to the alphabetical order:

"AA","Aa","aa","Development","development"
Michael
  • 10,063
  • 18
  • 65
  • 104
2

Simply use

java.util.Collections.sort(list)

without String.CASE_INSENSITIVE_ORDER comparator parameter.

L. G.
  • 9,642
  • 7
  • 56
  • 78
1

I recently answered a similar question here. Applying the same approach to your problem would yield following solution:

list.sort(
  p2Ord(stringOrd, stringOrd).comap(new F<String, P2<String, String>>() {
    public P2<String, String> f(String s) {
      return p(s.toLowerCase(), s);
    }
  })
);
Community
  • 1
  • 1
missingfaktor
  • 90,905
  • 62
  • 285
  • 365
  • The problem is that “AA” is equals to “aa”. Strings appear in the result according to the order of adding for the same values, and it is not correct: "aa","AA","Aa","development","Development" You should use additional compare to distinguish "AA" and "aa". – Michael Jun 24 '12 at 10:59
  • Here is the output of my above code: `[AA, Aa, aa, Development, development]`. Matches what's expected? – missingfaktor Jun 24 '12 at 11:01
  • @Michael, please see the linked answer to understand how this works. – missingfaktor Jun 24 '12 at 11:10
  • @Michael, in simple terms: `p(s.toLowerCase(), s)` says "first try comparing the lower case representations. If they turn out to be equal, try direct comparing strings themselves." – missingfaktor Jun 24 '12 at 11:11
  • Thanks! Any case, suggestion provided by Stephen is simpler and readable :) – Michael Jun 24 '12 at 12:10
  • I'd say it's [easier, not simpler](http://www.infoq.com/presentations/Simple-Made-Easy). ;-) – missingfaktor Jun 24 '12 at 13:35
  • @Michael, with Java-8, this code would become `list.sortedBy(s -> { Pair.of(s.toLowerCase(), s))`. `sortedBy` is being added to the standard library. – missingfaktor Jun 26 '12 at 17:33
  • @missingfaktor - Simplicity (like beauty) is in the eye of the beholder. What is simple to you is not necessarily simple to other people, and vice versa. – Stephen C Apr 25 '13 at 03:21
  • While true, in this context, it's a blanket statement. Please see the talk I linked to know how simplicity (or some aspects thereof) can be objective. – missingfaktor Apr 25 '13 at 05:11
  • Going around downvoting answers? Good. Carry on. – missingfaktor Apr 25 '13 at 12:38