56

I would like to sort and binary search a static array of strings via the String.CompareTo comparator.

The problem is that both sorting, and binary searching requires that a Comparator object be passed in -- So how do I pass in the built in string comparator?

0

13 Answers 13

55

Solution for Java 8 based on java.util.Comparator.comparing(...):

Comparator<String> c = Comparator.comparing(String::toString);

or

Comparator<String> c = Comparator.comparing((String x) -> x);
Sign up to request clarification or add additional context in comments.

2 Comments

Or Comparator.comparing(Function.identity())
Or String::compareTo Comparator<String> c = String::compareTo I think inlining is more readable than creating a variable for it: myListOfText.sort(String::compareTo);
51

You may write your own comparator

public class ExampleComparator  implements Comparator<String> {
  public int compare(String obj1, String obj2) {
    if (obj1 == obj2) {
        return 0;
    }
    if (obj1 == null) {
        return -1;
    }
    if (obj2 == null) {
        return 1;
    }
    return obj1.compareTo(obj2);
  }
}

5 Comments

Comparator is a generic type, so ExampleComparator should probably implement Comparator<String> to avoid warnings.
For string comparator, keep in mind to lowercase (or uppercase) string before compare them otherwise you should get this order A-Za-z
Need to implement equals() too.
Are you sure that you are supposed to return -1 in case that obj1==null && obj2==null, though?
Based on @towi's comment on Nov 24 '17: If obj1 == obj2 then it is true and thus resulting 0 when both of them are equals null!
23

The Arrays class has versions of sort() and binarySearch() which don't require a Comparator. For example, you can use the version of Arrays.sort() which just takes an array of objects. These methods call the compareTo() method of the objects in the array.

Comments

21

Ok this is a few years later but with java 8 you can use Comparator.naturalOrder():

http://docs.oracle.com/javase/8/docs/api/java/util/Comparator.html#naturalOrder--

From javadoc:

static <T extends Comparable<? super T>> Comparator<T> naturalOrder()

Returns a comparator that compares Comparable objects in natural order. The returned comparator is serializable and throws NullPointerException when comparing null.

1 Comment

Links to potential answers are always welcome, but please add most important parts here in case link gets removed.
14

If you do find yourslef needing a Comparator, and you already use Guava, you can use Ordering.natural().

Comments

11

This is a generic Comparator for any kind of Comparable object, not just String:

package util;

import java.util.Comparator;

/**
 * The Default Comparator for classes implementing Comparable.
 *
 * @param <E> the type of the comparable objects.
 *
 * @author Michael Belivanakis (michael.gr)
 */
public final class DefaultComparator<E extends Comparable<E>> implements Comparator<E>
{
    @SuppressWarnings( "rawtypes" )
    private static final DefaultComparator<?> INSTANCE = new DefaultComparator();

    /**
     * Get an instance of DefaultComparator for any type of Comparable.
     *
     * @param <T> the type of Comparable of interest.
     *
     * @return an instance of DefaultComparator for comparing instances of the requested type.
     */
    public static <T extends Comparable<T>> Comparator<T> getInstance()
    {
        @SuppressWarnings("unchecked")
        Comparator<T> result = (Comparator<T>)INSTANCE;
        return result;
    }

    private DefaultComparator()
    {
    }

    @Override
    public int compare( E o1, E o2 )
    {
        if( o1 == o2 )
            return 0;
        if( o1 == null )
            return 1;
        if( o2 == null )
            return -1;
        return o1.compareTo( o2 );
    }
}

How to use with String:

Comparator<String> stringComparator = DefaultComparator.getInstance();

2 Comments

@Sharcoux I see! C-:=
Could be nice to add the following code to that class: public static <T extends Comparable<T>> Comparator<T> getReversedInstance() { return Collections.reverseOrder((Comparator<T>) getInstance()); }
10

Again, don't need the comparator for Arrays.binarySearch(Object[] a, Object key) so long as the types of objects are comparable, but with lambda expressions this is now way easier.

Simply replace the comparator with the method reference: String::compareTo

E.g.:

Arrays.binarySearch(someStringArray, "The String to find.", String::compareTo);

You could also use

Arrays.binarySearch(someStringArray, "The String to find.", (a,b) -> a.compareTo(b));

but even before lambdas, there were always anonymous classes:

Arrays.binarySearch(
                someStringArray,
                "The String to find.",
                new Comparator<String>() {
                    @Override
                    public int compare(String o1, String o2) {
                        return o1.compareTo(o2);
                    }
                });

Comments

6

Also, if you want case-insensitive comparison, in recent versions of Java the String class contains a public static final field called CASE_INSENSITIVE_ORDER which is of type Comparator<String>, as I just recently found out. So, you can get your job done using String.CASE_INSENSITIVE_ORDER.

1 Comment

@tallseth this is the right answer only if you are interested in case-insensitive search, and you are using a recent version of java. If what you need is case-sensitive search, or if you are stuck with some old version of java, then this is not the right answer for you.
3

We can use the String.CASE_INSENSITIVE_ORDER comparator to compare the strings in case insensitive order.

Arrays.binarySearch(someStringArray, "The String to find.",String.CASE_INSENSITIVE_ORDER);

Comments

3

To generalize the good answer of Mike Nakis with String.CASE_INSENSITIVE_ORDER, you can also use :

Collator.getInstance();

See Collator

Comments

2

I find the most clean way is to use lambda expression.

Like this: strings.sort((a, b) -> a.compareTo(b));


If you want to know more—

In javascript or other functional languages, we can simply pass a function as an argument, that is, compareTo is itself a Comparator.

In java, functions are not first-class citizens. Therefore, you need to wrap it in a class that subclasses Comparator and define the method as the only method of that class.

Certainly it looks weird and verbose, b/c OOP is not designed to do something like this. Lambda expression does exactly that (subclassing, defining the method) behind the scene, although the expression itself looks the same as in functional language.

Comments

0

Regarding Nambari's answer there was a mistake. If you compare values using double equal sign == program will never reach compare method, unless someone will use new keyword to create String object which is not the best practice. This might be a bit better solution:

public int compare(String o1, String o2) {
        if (o1 == null && o2 == null){return 0;}
        if (o1 == null) { return -1;}
        if (o2 == null) { return 1;}
        return o1.compareTo(o2);
    }

P.S. Thanks for comments ;)

2 Comments

Although this code may answer the question, providing additional context regarding why and/or how it answers the question would significantly improve its long-term value. Please edit your answer to add some explanation.
How is this effectively any different from Nambari's answer?
-2

You can use the StringUtils.compare("a", "b")

1 Comment

It should be declared which package the StringUtils belongs to. My IDE lists 10 different ones. For me the answer works with org.apache.commons.lang3.StringUtils.

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.