سؤال

I need to write a static method in a class MinTester that computes the "smallest" string from an ArrayList collection using a comparator object:

public static String min(ArrayList<String> list, Comparator<String> comp)

I cannot use the Collections class to compute the minimum.

Here is what I have so far.

public class MinTester 
{
    public static String min(ArrayList<String> list, Comparator<String> comp)
    {
        String shortest = list.get(0);

        for(String str : list) {
            if ( comp.compare(str, shortest) < 0) {
                shortest = str;
            }
        }
        return shortest;
    }
}

I am not getting any errors here from the method, So I try to test it in Main with this. I get this error when trying to pass comp: Variable comp may not have been initialized

public static void main(String[] args)
{
    // TODO code application logic here

    MinTester s = new MinTester();
    Comparator<String> comp;
    ArrayList<String> list = new ArrayList<>();

    list.add("a");
    list.add("ab");
    list.add("abc");
    list.add("abcd");

    String a = s.min(list,comp);//Error: Variable comp may not have been initialized

    System.out.println(a);
}

Heres where I run into my problem.

I try

Comparator<String> comp = new Comparator<>();//Error:Comparator is abstract, cannot be instantiated
Comparator<String> comp = new MinTester();//Error: MinTester cannot be converted to Comparator<String>

Can anyone tell me the proper way to handle this Comparator? Im not sure if Im just trying to initialize it incorrectly, or if I'm missing something in my MinTester class.

هل كانت مفيدة؟

المحلول

You should write a class that implements Comparator<String> for this. A quick approach using anonymous class:

String a = s.min(list, new Comparator<String>() {
    @Override
    public int compare(String s1, String s2) {
        return s1.compareTo(s2);
    }
});

Since you need to compare based on String length, just change the comparison logic in the compare method:

String a = s.min(list, new Comparator<String>() {
    @Override
    public int compare(String s1, String s2) {
        return (s1.length() > s2.length()) ? 1 : (s1.length() < s2.length()) ? -1 : 0;
    }
});

If you happen to use Java 7, then use Integer#compare:

String a = s.min(list, new Comparator<String>() {
    @Override
    public int compare(String s1, String s2) {
        return Integer.compare(s1.length(), s2.length());
    }
});

If you use Java 8, you can use a lambda expression:

String a = s.min(list, (s1, s2) -> Integer.compare(s1.length(), s2.length()));

نصائح أخرى

Comparator is an interface; different classes can implement it in different ways to perform different kinds of comparisons. The reason why your method takes a Comparator is so that the caller can choose how the strings should be compared. Pass in a Comparator that does lexical (aka alphabetical) comparison, and you'll get the first string in lexical order. Pass in a Comparator that looks at string length, and you'll get the shortest string.

Since the String class already implements the Comparable interface — a sort of sibling to Comparator that lets a class define its own comparison method — here's a handy generic class that lets you use any Comparable through the Comparator interface:

public final class ComparableComparator<T extends Comparable<T>> implements Comparator<T> {
    @Override
    public int compare(final T a, final T b) {
        return a.compareTo(b);
    }
}

Pass one of those into your method and it'll compare the strings using the String class's own compareTo method.

Edit: In Java 8 or later, the Comparator.naturalOrder() method gives you the same thing, so you don't need to write the class above.

You do not need to use Comparator, at least not unless you want to modify the natural ordering of the string comparisons. Use the compareTo() method for the String class instead.

if (str.compareTo(shortest) < 0) {
     shortest = str;
}

If at all you wish to modify the natural ordering, you can create a class which implements the Comparator interface and then pass an instance of this class to the compare() method. You can also define your own logic for the comparisons.

public class StringDescComparator implements Comparator<String> {
    @Override
    public int compare(String str1, String str2) {
        // return str1.compareTo(str2);      // For natural ordering
        return -1 * str1.compareTo(str2);    // For reversed ordering
    }
}

Then you can use an instance of the above class to compare in the descending order such that: "b" < "a"

Comparator comp = new StringDescComparator();
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top